#ifndef __MEDIAPROP_H__ #define __MEDIAPROP_H__ // These should be moved into some central location #define PIDISI_CX 0x00000003L // VT_UI4 #define PIDISI_CY 0x00000004L // VT_UI4 #define PIDISI_FRAME_COUNT 0x0000000CL // VT_LPWSTR #define PIDISI_DIMENSIONS 0x0000000DL // VT_LPWSTR #define IsEqualSCID(a, b) (((a).pid == (b).pid) && IsEqualIID((a).fmtid, (b).fmtid) ) typedef struct { const SHCOLUMNID *pscid; LPCWSTR pszName; // Propstg string name for this property. VARTYPE vt; // Note that the type of a given FMTID/PID pair is a known, fixed value BOOL bEnumerate; // We don't want to enumerate alias properties. } COLMAP; #define DEFINE_SCID(name, fmtid, pid) const SHCOLUMNID name = { fmtid, pid } DEFINE_SCID(SCID_Author, PSGUID_SUMMARYINFORMATION, PIDSI_AUTHOR); DEFINE_SCID(SCID_Title, PSGUID_SUMMARYINFORMATION, PIDSI_TITLE); DEFINE_SCID(SCID_Comment, PSGUID_SUMMARYINFORMATION, PIDSI_COMMENTS); DEFINE_SCID(SCID_Category, PSGUID_DOCUMENTSUMMARYINFORMATION, PIDDSI_CATEGORY); DEFINE_SCID(SCID_MUSIC_Artist, PSGUID_MUSIC, PIDSI_ARTIST); DEFINE_SCID(SCID_MUSIC_Album, PSGUID_MUSIC, PIDSI_ALBUM); DEFINE_SCID(SCID_MUSIC_Year, PSGUID_MUSIC, PIDSI_YEAR); DEFINE_SCID(SCID_MUSIC_Track, PSGUID_MUSIC, PIDSI_TRACK); DEFINE_SCID(SCID_MUSIC_Genre, PSGUID_MUSIC, PIDSI_GENRE); DEFINE_SCID(SCID_MUSIC_Lyrics, PSGUID_MUSIC, PIDSI_LYRICS); DEFINE_SCID(SCID_DRM_Protected, PSGUID_DRM, PIDDRSI_PROTECTED); DEFINE_SCID(SCID_DRM_Description, PSGUID_DRM, PIDDRSI_DESCRIPTION); DEFINE_SCID(SCID_DRM_PlayCount, PSGUID_DRM, PIDDRSI_PLAYCOUNT); DEFINE_SCID(SCID_DRM_PlayStarts, PSGUID_DRM, PIDDRSI_PLAYSTARTS); DEFINE_SCID(SCID_DRM_PlayExpires, PSGUID_DRM, PIDDRSI_PLAYEXPIRES); DEFINE_SCID(SCID_VIDEO_StreamName, PSGUID_VIDEO, PIDVSI_STREAM_NAME); DEFINE_SCID(SCID_VIDEO_FrameRate, PSGUID_VIDEO, PIDVSI_FRAME_RATE); DEFINE_SCID(SCID_VIDEO_Bitrate, PSGUID_VIDEO, PIDVSI_DATA_RATE); DEFINE_SCID(SCID_VIDEO_SampleSize, PSGUID_VIDEO, PIDVSI_SAMPLE_SIZE); DEFINE_SCID(SCID_VIDEO_Compression, PSGUID_VIDEO, PIDVSI_COMPRESSION); DEFINE_SCID(SCID_AUDIO_Format, PSGUID_AUDIO, PIDASI_FORMAT); DEFINE_SCID(SCID_AUDIO_Duration, PSGUID_AUDIO, PIDASI_TIMELENGTH); //100ns units, not milliseconds. VT_UI8, not VT_UI4 DEFINE_SCID(SCID_AUDIO_Bitrate, PSGUID_AUDIO, PIDASI_AVG_DATA_RATE); DEFINE_SCID(SCID_AUDIO_SampleRate, PSGUID_AUDIO, PIDASI_SAMPLE_RATE); DEFINE_SCID(SCID_AUDIO_SampleSize, PSGUID_AUDIO, PIDASI_SAMPLE_SIZE); DEFINE_SCID(SCID_AUDIO_ChannelCount, PSGUID_AUDIO, PIDASI_CHANNEL_COUNT); DEFINE_SCID(SCID_IMAGE_Width, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_CX); DEFINE_SCID(SCID_IMAGE_Height, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_CY); DEFINE_SCID(SCID_IMAGE_Dimensions, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_DIMENSIONS); DEFINE_SCID(SCID_IMAGE_FrameCount, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_FRAME_COUNT); // Docsummary props const COLMAP g_CM_Category = { &SCID_Category, L"Category", VT_LPWSTR, FALSE}; // Alias property of Genre // SummaryProps const COLMAP g_CM_Author = { &SCID_Author, L"Author", VT_LPWSTR, FALSE}; // Alias property of Artist const COLMAP g_CM_Title = { &SCID_Title, L"Title", VT_LPWSTR, TRUE}; const COLMAP g_CM_Comment = { &SCID_Comment, L"Description", VT_LPWSTR, TRUE}; // Music props const COLMAP g_CM_Artist = { &SCID_MUSIC_Artist, L"Author", VT_LPWSTR, TRUE}; const COLMAP g_CM_Album = { &SCID_MUSIC_Album, L"AlbumTitle", VT_LPWSTR, TRUE}; const COLMAP g_CM_Year = { &SCID_MUSIC_Year, L"Year", VT_LPWSTR, TRUE}; const COLMAP g_CM_Track = { &SCID_MUSIC_Track, L"Track", VT_UI4, TRUE}; // NB: This is exposed as a WMT_ATTRTYPE_STRING for mp3. We may need to change it. const COLMAP g_CM_Genre = { &SCID_MUSIC_Genre, L"Genre", VT_LPWSTR, TRUE}; const COLMAP g_CM_Lyrics = { &SCID_MUSIC_Lyrics, L"Lyrics", VT_LPWSTR, TRUE}; // Audio props const COLMAP g_CM_Format = { &SCID_AUDIO_Format, L"Format", VT_LPWSTR, TRUE}; const COLMAP g_CM_Duration = { &SCID_AUDIO_Duration, L"Duration", VT_UI8, TRUE}; const COLMAP g_CM_Bitrate = { &SCID_AUDIO_Bitrate, L"Bitrate", VT_UI4, TRUE}; const COLMAP g_CM_SampleRate = { &SCID_AUDIO_SampleRate, L"SampleRate", VT_UI4, TRUE}; // samples per sec const COLMAP g_CM_SampleSize = { &SCID_AUDIO_SampleSize, L"SampleSize", VT_UI4, TRUE}; const COLMAP g_CM_ChannelCount ={ &SCID_AUDIO_ChannelCount, L"ChannelCount", VT_UI4, TRUE}; // Video props const COLMAP g_CM_StreamName = { &SCID_VIDEO_StreamName, L"StreamName", VT_LPWSTR, TRUE}; const COLMAP g_CM_FrameRate = { &SCID_VIDEO_FrameRate, L"FrameRate", VT_UI4, TRUE}; const COLMAP g_CM_SampleSizeV = { &SCID_VIDEO_SampleSize, L"SampleSize", VT_UI4, TRUE}; // different from audio sample simple const COLMAP g_CM_BitrateV = { &SCID_VIDEO_Bitrate, L"Bitrate", VT_UI4, TRUE}; // different from audio bitrate const COLMAP g_CM_Compression = { &SCID_VIDEO_Compression, L"Compression", VT_LPWSTR, TRUE}; // Image props const COLMAP g_CM_Width = { &SCID_IMAGE_Width, L"Width", VT_UI4, TRUE}; const COLMAP g_CM_Height = { &SCID_IMAGE_Height, L"Height", VT_UI4, TRUE}; const COLMAP g_CM_Dimensions = { &SCID_IMAGE_Dimensions, L"Dimensions", VT_LPWSTR, TRUE}; const COLMAP g_CM_FrameCount = { &SCID_IMAGE_FrameCount, L"FrameCount", VT_UI4, TRUE}; // DRM props const COLMAP g_CM_Protected = { &SCID_DRM_Protected, L"Protected", VT_BOOL, TRUE}; const COLMAP g_CM_DRMDescription={&SCID_DRM_Description, L"DRMDescription", VT_LPWSTR, TRUE}; const COLMAP g_CM_PlayCount = { &SCID_DRM_PlayCount, L"PlayCount", VT_UI4, TRUE}; const COLMAP g_CM_PlayStarts = { &SCID_DRM_PlayStarts, L"PlayStarts", VT_FILETIME,TRUE}; const COLMAP g_CM_PlayExpires = { &SCID_DRM_PlayExpires, L"PlayExpires", VT_FILETIME,TRUE}; // Describes each of the property sets an IPropertySetStorage uses. typedef struct { GUID fmtid; // fmtid for this property set const COLMAP **pcmProps; // List of all properties that exist in this set ULONG cNumProps; } PROPSET_INFO; enum MUSICPROPSTG_AUTHLEVEL { AUTH = 0, NON_AUTH }; enum PROPSTG_STATE { CLOSED = 0, OPENED_SHARED, OPENED_DENYREAD, OPENED_DENYWRITE, OPENED_DENYALL }; class CMediaPropSetStg; // Base property storage implementation. class CMediaPropStorage : public IPropertyStorage, IQueryPropertyFlags { public: // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); //IPropertyStorage STDMETHODIMP ReadMultiple (ULONG cpspec, const PROPSPEC rgpspec[], PROPVARIANT rgvar[]); STDMETHODIMP WriteMultiple (ULONG cpspec, PROPSPEC const rgpspec[], const PROPVARIANT rgvar[], PROPID propidNameFirst); STDMETHODIMP DeleteMultiple(ULONG cpspec, PROPSPEC const rgpspec[]); STDMETHODIMP ReadPropertyNames (ULONG cpspec, PROPID const rgpropid[], LPWSTR rglpwstrName[]); STDMETHODIMP WritePropertyNames (ULONG cpspec, PROPID const rgpropid[], LPWSTR const rglpwstrName[]); STDMETHODIMP DeletePropertyNames(ULONG cpspec, PROPID const rgpropid[]); STDMETHODIMP SetClass(REFCLSID clsid); STDMETHODIMP Commit(DWORD grfCommitFlags); STDMETHODIMP Revert(); STDMETHODIMP Enum(IEnumSTATPROPSTG **ppenum); STDMETHODIMP Stat(STATPROPSETSTG *pstatpropstg); STDMETHODIMP SetTimes(FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime); // IQueryPropertyFlags STDMETHODIMP GetFlags(const PROPSPEC *pspec, SHCOLSTATEF *pcsFlags); CMediaPropStorage(CMediaPropSetStg *ppssParent, CMediaPropStorage *ppsAuthority, REFFMTID fmtid, const COLMAP **ppcmPropInfo, DWORD cNumProps, DWORD dwMode, CRITICAL_SECTION *pcs); HRESULT SetProperty(PROPSPEC *ppspec, PROPVARIANT *pvar);//called by the parent to set the initial data HRESULT QuickLookup(PROPSPEC *ppspec, PROPVARIANT **ppvar); private: ~CMediaPropStorage(); HRESULT Open(DWORD dwShareMode, DWORD dwOpenMode, IPropertyStorage **ppPropStg); void _ResetPropStorage(); //Resets the Propstorage to a known empty state HRESULT CopyPropStorageData(PROPVARIANT *pvarProps); void OnClose(); HRESULT DoCommit(DWORD grfCommitFlags, FILETIME *ftFlushTime, PROPVARIANT *pVarProps, BOOL *pbDirtyFlags);//flush the data to the parent HRESULT LookupProp(const PROPSPEC *pspec, const COLMAP **ppcmName, PROPVARIANT **ppvarReadData, PROPVARIANT **ppvarWriteData, BOOL **ppbDirty, BOOL bPropertySet); BOOL IsDirectMode(); BOOL IsSpecialProperty(const PROPSPEC *pspec); HRESULT _EnsureSlowPropertiesLoaded(); virtual BOOL _IsSlowProperty(const COLMAP *pPInfo); LONG _cRef; COLMAP const **_ppcmPropInfo; PROPVARIANT *_pvarProps, *_pvarChangedProps; PROPVARIANT _varCodePage; BOOL *_pbDirtyFlags; ULONG _cNumProps; MUSICPROPSTG_AUTHLEVEL _authLevel; CMediaPropStorage *_ppsAuthority; CMediaPropSetStg *_ppssParent; FMTID _fmtid; FILETIME _ftLastCommit; PROPSTG_STATE _state; DWORD _dwMode; BOOL _bRetrievedSlowProperties; HRESULT _hrSlowProps; CRITICAL_SECTION *_pcs; // The parent storage set's critical section. friend class CMediaPropSetStg; }; // Base property set storage implementation. class CMediaPropSetStg : public IPersistFile, IPropertySetStorage, IWMReaderCallback { public: CMediaPropSetStg(); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IPersist STDMETHODIMP GetClassID(CLSID *pClassID); // IPersistFile STDMETHODIMP IsDirty(void); STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode); STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember); STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName); STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName); // IPropertySetStorage STDMETHODIMP Create(REFFMTID fmtid, const CLSID * pclsid, DWORD grfFlags, DWORD grfMode, IPropertyStorage** ppPropStg); STDMETHODIMP Open(REFFMTID fmtid, DWORD grfMode, IPropertyStorage** ppPropStg); STDMETHODIMP Delete(REFFMTID fmtid); STDMETHODIMP Enum(IEnumSTATPROPSETSTG** ppenum); // IWMReaderCallBack STDMETHODIMP OnStatus(WMT_STATUS Staus, HRESULT hr, WMT_ATTR_DATATYPE dwType, BYTE *pValue, void *pvContext); STDMETHODIMP OnSample(DWORD dwOutputNum, QWORD cnsSampleTime, QWORD cnsSampleDuration, DWORD dwFlags, INSSBuffer *pSample, void* pcontext); virtual HRESULT FlushChanges(REFFMTID fmtid, LONG cNumProps, const COLMAP **pcmapInfo, PROPVARIANT *pVarProps, BOOL *pbDirtyFlags); HRESULT Init(); virtual BOOL _IsSlowProperty(const COLMAP *pPInfo); protected: HRESULT _ResolveFMTID(REFFMTID fmtid, CMediaPropStorage **ppps); HRESULT _PopulateProperty(const COLMAP *pPInfo, PROPVARIANT *pvar); BOOL _bIsWritable; WCHAR _wszFile[MAX_PATH]; BOOL _bHasBeenPopulated; BOOL _bSlowPropertiesExtracted; HRESULT _hrSlowProps; HRESULT _hrPopulated; UINT _cPropertyStorages; CMediaPropStorage **_propStg; const PROPSET_INFO *_pPropStgInfo; // Indicates which propstorages to create, etc... HANDLE _hFileOpenEvent; ~CMediaPropSetStg(); private: HRESULT _ResetPropertySet(); HRESULT _CreatePropertyStorages(); virtual HRESULT _PopulatePropertySet(); virtual HRESULT _PopulateSlowProperties(); virtual HRESULT _PreCheck(); LONG _cRef; DWORD _dwMode; // This property handler needes to operate in a FTA because of the content indexing service. If // we're created in an STA, it turns out they can't properly impersonate a user across apartment // boundaries. // This is a critical section we use to provide very "simple" synchronized access to our internal // members. Basically, we just wrap every public interface member in Enter/Leave. The WMSDK // doesn't throw any exceptions, so we don't need any try-finally's (and hopefully the AVI and WAV // code doesn't either). // All public interface members in the CMediaPropStorage class are also protected by this same // critical section. CRITICAL_SECTION _cs; friend class CMediaPropStorage; }; // Class used to enumerate through all COLMAPs for the properties supported by a propertysetstorage // // Used internally by a PSS when populating properties. class CEnumAllProps { public: CEnumAllProps(const PROPSET_INFO *pPropSets, UINT cPropSets); const COLMAP *Next(); private: const PROPSET_INFO *_pPropSets; UINT _cPropSets; UINT _iPropSetPos; UINT _iPropPos; }; #endif //__MEDIAPROP_H__