#include "pch.h" #include "thisdll.h" #include "ids.h" #include "MediaProp.h" #define MAX_DESCRIPTOR 256 #include #include #include // Wav file stuff typedef struct { DWORD dwSize; LONG nLength; // milliseconds TCHAR szWaveFormat[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; PWAVEFORMATEX pwfx; } WAVEDESC; STDMETHODIMP GetWaveInfo(IN LPCTSTR pszFile, OUT WAVEDESC *p); STDMETHODIMP GetWaveProperty(IN REFFMTID reffmtid, IN PROPID propid, IN const WAVEDESC* pWave, OUT PROPVARIANT* pVar); const COLMAP* c_rgAVWavAudioProps[] = { {&g_CM_Duration}, {&g_CM_Bitrate}, {&g_CM_SampleRate}, {&g_CM_SampleSize}, {&g_CM_ChannelCount}, {&g_CM_Format}, }; const PROPSET_INFO g_rgAVWavPropStgs[] = { { PSGUID_AUDIO, c_rgAVWavAudioProps, ARRAYSIZE(c_rgAVWavAudioProps)}, }; // Wav files // Avi file stuff typedef struct { DWORD dwSize; LONG nLength; // milliseconds LONG nWidth; // pixels LONG nHeight; // pixels LONG nBitDepth; LONG cFrames; LONG nFrameRate; // frames/1000 seconds LONG nDataRate; // bytes/second TCHAR szCompression[MAX_DESCRIPTOR]; TCHAR szStreamName[MAX_DESCRIPTOR]; TCHAR szWaveFormat[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; PWAVEFORMATEX pwfx; } AVIDESC; STDMETHODIMP GetAviInfo(IN LPCTSTR pszFile, OUT AVIDESC *p); STDMETHODIMP GetAviProperty(IN REFFMTID reffmtid, IN PROPID propid, IN const AVIDESC* pAvi, OUT PROPVARIANT* pVar); const COLMAP* c_rgAVAviAudioProps[] = { {&g_CM_Duration}, {&g_CM_SampleSize}, {&g_CM_Bitrate}, {&g_CM_Format}, }; const COLMAP* c_rgAVAviImageProps[] = { {&g_CM_Width}, {&g_CM_Height}, {&g_CM_Dimensions}, }; const COLMAP* c_rgAVAviVideoProps[] = { {&g_CM_FrameCount}, {&g_CM_FrameRate}, {&g_CM_Compression}, {&g_CM_BitrateV}, {&g_CM_SampleSizeV}, }; const COLMAP* c_rgAVAviSummaryProps[] = { {&g_CM_Title}, }; const PROPSET_INFO g_rgAVAviPropStgs[] = { { PSGUID_AUDIO, c_rgAVAviAudioProps, ARRAYSIZE(c_rgAVAviAudioProps)}, { PSGUID_SUMMARYINFORMATION, c_rgAVAviSummaryProps, ARRAYSIZE(c_rgAVAviSummaryProps)}, { PSGUID_VIDEO, c_rgAVAviVideoProps, ARRAYSIZE(c_rgAVAviVideoProps)}, { PSGUID_IMAGESUMMARYINFORMATION, c_rgAVAviImageProps, ARRAYSIZE(c_rgAVAviImageProps)}, }; // avi // Midi file stuff // Note: Midi files are REALLLLLY slow. typedef struct { LONG nLength; TCHAR szMidiCopyright[MAX_DESCRIPTOR]; TCHAR szMidiSequenceName[MAX_DESCRIPTOR]; } MIDIDESC; STDMETHODIMP GetMidiInfo(IN LPCTSTR pszFile, OUT MIDIDESC *p); STDMETHODIMP GetMidiProperty(IN REFFMTID reffmtid, IN PROPID propid, IN const MIDIDESC* pMidi, OUT PROPVARIANT* pVar); const COLMAP* c_rgAVMidiAudioProps[] = { {&g_CM_Duration}, }; const COLMAP* c_rgAVMidiSummaryProps[] = { {&g_CM_Title}, // SequenceName }; const PROPSET_INFO g_rgAVMidiPropStgs[] = { { PSGUID_AUDIO, c_rgAVMidiAudioProps, ARRAYSIZE(c_rgAVMidiAudioProps)}, { PSGUID_SUMMARYINFORMATION, c_rgAVMidiSummaryProps, ARRAYSIZE(c_rgAVMidiSummaryProps)}, }; // Midi #define FOURCC_INFO mmioFOURCC('I','N','F','O') #define FOURCC_DISP mmioFOURCC('D','I','S','P') #define FOURCC_IARL mmioFOURCC('I','A','R','L') #define FOURCC_IART mmioFOURCC('I','A','R','T') #define FOURCC_ICMS mmioFOURCC('I','C','M','S') #define FOURCC_ICMT mmioFOURCC('I','C','M','T') #define FOURCC_ICOP mmioFOURCC('I','C','O','P') #define FOURCC_ICRD mmioFOURCC('I','C','R','D') #define FOURCC_ICRP mmioFOURCC('I','C','R','P') #define FOURCC_IDIM mmioFOURCC('I','D','I','M') #define FOURCC_IDPI mmioFOURCC('I','D','P','I') #define FOURCC_IENG mmioFOURCC('I','E','N','G') #define FOURCC_IGNR mmioFOURCC('I','G','N','R') #define FOURCC_IKEY mmioFOURCC('I','K','E','Y') #define FOURCC_ILGT mmioFOURCC('I','L','G','T') #define FOURCC_IMED mmioFOURCC('I','M','E','D') #define FOURCC_INAM mmioFOURCC('I','N','A','M') #define FOURCC_IPLT mmioFOURCC('I','P','L','T') #define FOURCC_IPRD mmioFOURCC('I','P','R','D') #define FOURCC_ISBJ mmioFOURCC('I','S','B','J') #define FOURCC_ISFT mmioFOURCC('I','S','F','T') #define FOURCC_ISHP mmioFOURCC('I','S','H','P') #define FOURCC_ISRC mmioFOURCC('I','S','R','C') #define FOURCC_ISRF mmioFOURCC('I','S','R','F') #define FOURCC_ITCH mmioFOURCC('I','T','C','H') #define FOURCC_VIDC mmioFOURCC('V','I','D','C') #define mmioWAVE mmioFOURCC('W','A','V','E') #define mmioFMT mmioFOURCC('f','m','t',' ') #define mmioDATA mmioFOURCC('d','a','t','a') #define MAXNUMSTREAMS 50 //#define _MIDI_PROPERTY_SUPPORT_ STDMETHODIMP GetMidiInfo(LPCTSTR pszFile, MIDIDESC *pmidi) { #ifdef _MIDI_PROPERTY_SUPPORT_ MCI_OPEN_PARMS mciOpen; /* Structure for MCI_OPEN command */ DWORD dwFlags; DWORD dw; MCIDEVICEID wDevID; MCI_STATUS_PARMS mciStatus; MCI_SET_PARMS mciSet; /* Structure for MCI_SET command */ MCI_INFO_PARMS mciInfo; /* Open a file with an explicitly specified device */ mciOpen.lpstrDeviceType = TEXT("sequencer"); mciOpen.lpstrElementName = pszFile; dwFlags = MCI_WAIT | MCI_OPEN_ELEMENT | MCI_OPEN_TYPE; dw = mciSendCommand((MCIDEVICEID)0, MCI_OPEN, dwFlags,(DWORD_PTR)(LPVOID)&mciOpen); if (dw) return E_FAIL; wDevID = mciOpen.wDeviceID; mciSet.dwTimeFormat = MCI_FORMAT_MILLISECONDS; dw = mciSendCommand(wDevID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR) (LPVOID) &mciSet); if (dw) { mciSendCommand(wDevID, MCI_CLOSE, 0L, (DWORD)0); return E_FAIL; } mciStatus.dwItem = MCI_STATUS_LENGTH; dw = mciSendCommand(wDevID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR) (LPTSTR) &mciStatus); if (dw) pmidi->nLength = 0; else pmidi->nLength = (UINT)mciStatus.dwReturn; mciInfo.dwCallback = 0; mciInfo.lpstrReturn = pmidi->szMidiCopyright; mciInfo.dwRetSize = sizeof(pmidi->szMidiCopyright); *mciInfo.lpstrReturn = 0; mciSendCommand(wDevID, MCI_INFO, MCI_INFO_COPYRIGHT, (DWORD_PTR)(LPVOID)&mciInfo); mciInfo.lpstrReturn = pmidi->szMidiCopyright; mciInfo.dwRetSize = sizeof(pmidi->szMidiSequenceName); *mciInfo.lpstrReturn = 0; mciSendCommand(wDevID, MCI_INFO, MCI_INFO_NAME, (DWORD_PTR)(LPVOID)&mciInfo); mciSendCommand(wDevID, MCI_CLOSE, 0L, (DWORD)0); return S_OK; #else _MIDI_PROPERTY_SUPPORT_ return E_FAIL; #endif _MIDI_PROPERTY_SUPPORT_ } STDMETHODIMP GetMidiProperty( IN REFFMTID reffmtid, IN PROPID pid, IN const MIDIDESC* pMidi, OUT PROPVARIANT* pVar) { HRESULT hr = S_OK; if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation)) { hr = S_OK; switch (pid) { case PIDASI_TIMELENGTH: if (0 >= pMidi->nLength) return E_FAIL; // This value is in milliseconds. // However, we define duration to be in 100ns units, so multiply by 10000. pVar->uhVal.LowPart = pMidi->nLength; pVar->uhVal.HighPart = 0; pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000; pVar->vt = VT_UI8; break; } } return hr; } HRESULT ReadWaveHeader(HMMIO hmmio, WAVEDESC *pwd) { BOOL bRet = FALSE; MMCKINFO mmckRIFF; MMCKINFO mmck; DWORD dwFormatSize; MMRESULT wError; ZeroMemory(pwd, sizeof(*pwd)); mmckRIFF.fccType = mmioWAVE; if ((wError = mmioDescend(hmmio, &mmckRIFF, NULL, MMIO_FINDRIFF))) { return E_FAIL; } mmck.ckid = mmioFMT; if ((wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK))) { return E_FAIL; } if (mmck.cksize < sizeof(WAVEFORMAT)) { return E_FAIL; } dwFormatSize = mmck.cksize; if (dwFormatSize <= 0x0000ffff) // (anything with a huge header is probably a corrupt file, so fail) { pwd->pwfx = (PWAVEFORMATEX)new BYTE[dwFormatSize]; if (pwd->pwfx) { if ((DWORD)mmioRead(hmmio, (HPSTR)pwd->pwfx, mmck.cksize) != mmck.cksize) { goto retErr; } if (pwd->pwfx->wFormatTag == WAVE_FORMAT_PCM) { if (dwFormatSize < sizeof(PCMWAVEFORMAT)) { goto retErr; } } else if ((dwFormatSize < sizeof(WAVEFORMATEX)) || (dwFormatSize < sizeof(WAVEFORMATEX) + pwd->pwfx->cbSize)) { goto retErr; } if ((wError = mmioAscend(hmmio, &mmck, 0))) { goto retErr; } mmck.ckid = mmioDATA; if ((wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK))) { goto retErr; } pwd->dwSize = mmck.cksize; return S_OK; } } retErr: if (pwd->pwfx) { delete [] (LPBYTE)pwd->pwfx; pwd->pwfx = NULL; } return E_FAIL; } // Retrieves text representation of format tag STDMETHODIMP GetWaveFormatTag(PWAVEFORMATEX pwfx, LPTSTR pszTag, IN ULONG cchTag) { ASSERT(pwfx); ASSERT(pszTag); ASSERT(cchTag); ACMFORMATTAGDETAILS aftd; ZeroMemory(&aftd, sizeof(aftd)); aftd.cbStruct = sizeof(ACMFORMATTAGDETAILSW); aftd.dwFormatTag = pwfx->wFormatTag; if (0 == acmFormatTagDetails(NULL, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG)) { // copy to output - ok if truncated. StringCchCopy(pszTag, cchTag, aftd.szFormatTag); return S_OK; } return E_FAIL; } STDMETHODIMP GetWaveInfo(IN LPCTSTR pszFile, OUT WAVEDESC *p) { HMMIO hmmio; if (NULL == (hmmio = mmioOpen((LPTSTR)pszFile, NULL, MMIO_ALLOCBUF | MMIO_READ))) return E_FAIL; HRESULT hr = ReadWaveHeader(hmmio, p); mmioClose(hmmio, 0); if (SUCCEEDED(hr) && p->pwfx) { // Retrieve text representation of format tag GetWaveFormatTag(p->pwfx, p->szWaveFormat, ARRAYSIZE(p->szWaveFormat)); } return hr; } STDMETHODIMP FreeWaveInfo(IN OUT WAVEDESC *p) { if (p->pwfx) { delete [] p->pwfx; p->pwfx = NULL; } return S_OK; } STDMETHODIMP _getWaveAudioProperty( IN REFFMTID reffmtid, IN PROPID pid, IN const PWAVEFORMATEX pwfx, OUT PROPVARIANT* pVar) { HRESULT hr = E_UNEXPECTED; TCHAR szBuf[MAX_DESCRIPTOR], szFmt[MAX_DESCRIPTOR]; PropVariantInit(pVar); *szBuf = *szFmt = 0; if (pwfx && IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation)) { hr = S_OK; switch (pid) { case PIDASI_AVG_DATA_RATE: if (0 >= pwfx->nAvgBytesPerSec) return E_FAIL; // Convert into bits per sec. pVar->ulVal = pwfx->nAvgBytesPerSec * 8; pVar->vt = VT_UI4; break; case PIDASI_SAMPLE_RATE: if (0 >= pwfx->nSamplesPerSec) return E_FAIL; // Samples per second (/1000 to get kHz) pVar->ulVal = pwfx->nSamplesPerSec; pVar->vt = VT_UI4; break; case PIDASI_SAMPLE_SIZE: if (0 >= pwfx->wBitsPerSample) return E_FAIL; // Bits per sample. pVar->ulVal = pwfx->wBitsPerSample; pVar->vt = VT_UI4; break; case PIDASI_CHANNEL_COUNT: { if (0 >= pwfx->nChannels) return E_FAIL; pVar->ulVal = pwfx->nChannels; pVar->vt = VT_UI4; break; } default: return E_UNEXPECTED; } } return hr; } STDMETHODIMP GetWaveProperty( IN REFFMTID reffmtid, IN PROPID pid, IN const WAVEDESC* pWave, OUT PROPVARIANT* pVar) { HRESULT hr = E_FAIL; TCHAR szBuf[MAX_DESCRIPTOR], szFmt[MAX_DESCRIPTOR]; PropVariantInit(pVar); *szBuf = *szFmt = 0; if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation)) { hr = S_OK; switch (pid) { case PIDASI_FORMAT: if (0 == *pWave->szWaveFormat) return E_FAIL; hr = SHStrDupW(pWave->szWaveFormat, &pVar->pwszVal); if (SUCCEEDED(hr)) pVar->vt = VT_LPWSTR; else return hr; break; // ISSUE: nLength is never filled in in GetWaveInfo, so this will always be zero. case PIDASI_TIMELENGTH: if (0 >= pWave->nLength) return E_FAIL; // This value is in milliseconds. // However, we define duration to be in 100ns units, so multiply by 10000. pVar->uhVal.LowPart = pWave->nLength; pVar->uhVal.HighPart = 0; pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000; pVar->vt = VT_UI8; break; default: hr = E_UNEXPECTED; } } if (FAILED(hr)) hr = _getWaveAudioProperty(reffmtid, pid, pWave->pwfx, pVar); return hr; } STDMETHODIMP ReadAviStreams(LPCTSTR pszFile, DWORD dwFileSize, AVIDESC *pAvi) { HRESULT hr; PAVIFILE pfile; PAVISTREAM pavi; PAVISTREAM rgpavis[MAXNUMSTREAMS]; // the current streams AVISTREAMINFO avsi; LONG timeStart; // cached start, end, length LONG timeEnd; int cpavi; int i; hr = AVIFileOpen(&pfile, pszFile, 0, 0L); if (FAILED(hr)) return hr; for (i = 0; i <= MAXNUMSTREAMS; i++) { if (AVIFileGetStream(pfile, &pavi, 0L, i) != AVIERR_OK) break; if (i == MAXNUMSTREAMS) { AVIStreamRelease(pavi); //DPF("Exceeded maximum number of streams"); break; } #pragma prefast(suppress:201, we already broke out when i == MAXNUMSTREAMS (PREfast bug 546)) rgpavis[i] = pavi; } // // Couldn't get any streams out of this file // if (i == 0) { //DPF("Unable to open any streams in %s", pszFile); if (pfile) AVIFileRelease(pfile); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } cpavi = i; // // Start with bogus times // timeStart = 0x7FFFFFFF; timeEnd = 0; // // Walk through and init all streams loaded // for (i = 0; i < cpavi; i++) { AVIStreamInfo(rgpavis[i], &avsi, sizeof(avsi)); switch (avsi.fccType) { case streamtypeVIDEO: { LONG cbFormat; LPBYTE lpFormat; ICINFO icInfo; HIC hic; DWORD dwTimeLen; if (AVIStreamFormatSize(rgpavis[i], 0, &cbFormat) == AVIERR_OK) { dwTimeLen = AVIStreamEndTime(rgpavis[i]) - AVIStreamStartTime(rgpavis[i]); pAvi->cFrames = avsi.dwLength; pAvi->nFrameRate = MulDiv(avsi.dwLength, 1000000, dwTimeLen); pAvi->nDataRate = MulDiv(dwFileSize, 1000000, dwTimeLen)/1024; pAvi->nWidth = avsi.rcFrame.right - avsi.rcFrame.left; pAvi->nHeight = avsi.rcFrame.bottom - avsi.rcFrame.top; // ok if truncated. StringCchCopy(pAvi->szStreamName, ARRAYSIZE(pAvi->szStreamName), avsi.szName); // Retrieve raster info (compression, bit depth). lpFormat = new BYTE[cbFormat]; if (lpFormat) { if (AVIStreamReadFormat(rgpavis[i], 0, lpFormat, &cbFormat) == AVIERR_OK) { hic = (HIC)ICLocate(FOURCC_VIDC, avsi.fccHandler, (BITMAPINFOHEADER*)lpFormat, NULL, (WORD)ICMODE_DECOMPRESS); if (hic || ((LPBITMAPINFOHEADER)lpFormat)->biCompression == 0) { if (((LPBITMAPINFOHEADER)lpFormat)->biCompression) { ICGetInfo(hic, &icInfo, sizeof(ICINFO)); ICClose(hic); // ok if truncated. StringCchCopy(pAvi->szCompression, ARRAYSIZE(pAvi->szCompression), icInfo.szName); } else { LoadString(m_hInst, IDS_AVI_UNCOMPRESSED, pAvi->szCompression, ARRAYSIZE(pAvi->szCompression)); } pAvi->nBitDepth = ((LPBITMAPINFOHEADER)lpFormat)->biBitCount; } } delete [] lpFormat; } } else hr = E_OUTOFMEMORY; break; } case streamtypeAUDIO: { LONG cbFormat; if (AVIStreamFormatSize(rgpavis[i], 0, &cbFormat) == AVIERR_OK) { pAvi->pwfx = (PWAVEFORMATEX) new BYTE[cbFormat]; if (pAvi->pwfx) { ZeroMemory(pAvi->pwfx, cbFormat); if (AVIStreamReadFormat(rgpavis[i], 0, pAvi->pwfx, &cbFormat) == 0) { GetWaveFormatTag(pAvi->pwfx, pAvi->szWaveFormat, ARRAYSIZE(pAvi->szWaveFormat)); } } } break; } default: break; } // // We're finding the earliest and latest start and end points for // our scrollbar. // timeStart = min(timeStart, AVIStreamStartTime(rgpavis[i])); timeEnd = max(timeEnd, AVIStreamEndTime(rgpavis[i])); } pAvi->nLength = (UINT)(timeEnd - timeStart); for (i = 0; i < cpavi; i++) { AVIStreamRelease(rgpavis[i]); } AVIFileRelease(pfile); return S_OK; } // Because some AVI programs don't export the correct headers, retrieving AVI info will take // an extremly long time on some files, we need to verify that the headers are available // before we call AVIFileOpen BOOL _ValidAviHeaderInfo(LPCTSTR pszFile) { BOOL fRet = FALSE; // Assume it is bad HMMIO hmmio = mmioOpen((LPWSTR)pszFile, NULL, MMIO_READ); if (hmmio) { MMCKINFO ckRIFF; if (mmioDescend(hmmio, &ckRIFF, NULL, 0) == 0) { if ((ckRIFF.ckid == FOURCC_RIFF) && (ckRIFF.fccType == formtypeAVI)) { MMCKINFO ckLIST; ckLIST.fccType = listtypeAVIHEADER; if (mmioDescend(hmmio, &ckLIST, &ckRIFF, MMIO_FINDLIST) == 0) { ckRIFF.ckid = ckidAVIMAINHDR; if (mmioDescend(hmmio, &ckRIFF, &ckLIST, MMIO_FINDCHUNK) == 0) { MainAVIHeader Hdr; ULONG cb = min(sizeof Hdr, ckRIFF.cksize); if (mmioRead(hmmio, (HPSTR)&Hdr, cb) == cb) { fRet = Hdr.dwFlags & AVIF_HASINDEX; } } } } } mmioClose(hmmio, 0); } return fRet; } STDMETHODIMP GetAviInfo(LPCTSTR pszFile, AVIDESC *pavi) { HRESULT hr = E_UNEXPECTED; if (_ValidAviHeaderInfo(pszFile)) { // Retrieve the file size HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { DWORD dwRet = GetLastError(); return ERROR_SUCCESS != dwRet ? HRESULT_FROM_WIN32(dwRet) : E_UNEXPECTED; } DWORD dwFileSize = GetFileSize((HANDLE)hFile, NULL); CloseHandle(hFile); AVIFileInit(); hr = ReadAviStreams(pszFile, dwFileSize, pavi); AVIFileExit(); } return hr; } STDMETHODIMP FreeAviInfo(IN OUT AVIDESC *p) { if (p->pwfx) { delete [] p->pwfx; p->pwfx = NULL; } return S_OK; } STDMETHODIMP GetAviProperty( IN REFFMTID reffmtid, IN PROPID pid, IN const AVIDESC* pAvi, OUT PROPVARIANT* pVar) { HRESULT hr = E_UNEXPECTED; TCHAR szBuf[MAX_DESCRIPTOR], szFmt[MAX_DESCRIPTOR]; PropVariantInit(pVar); *szBuf = *szFmt = 0; if (IsEqualGUID(reffmtid, FMTID_SummaryInformation)) { hr = S_OK; switch (pid) { case PIDSI_TITLE: if (0 == *pAvi->szStreamName) return E_FAIL; hr = SHStrDupW(pAvi->szStreamName, &pVar->pwszVal); if (SUCCEEDED(hr)) pVar->vt = VT_LPWSTR; else return hr; default: hr = E_UNEXPECTED; } } else if (IsEqualGUID(reffmtid, FMTID_ImageSummaryInformation)) { hr = S_OK; switch (pid) { case PIDISI_CX: if (0 >= pAvi->nWidth) return E_FAIL; pVar->ulVal = pAvi->nWidth; pVar->vt = VT_UI4; break; case PIDISI_CY: if (0 >= pAvi->nHeight) return E_FAIL; pVar->ulVal = pAvi->nHeight; pVar->vt = VT_UI4; break; case PIDISI_FRAME_COUNT: if (0 >= pAvi->cFrames) return E_FAIL; pVar->ulVal = pAvi->cFrames; pVar->vt = VT_UI4; break; case PIDISI_DIMENSIONS: if ((0 >= pAvi->nHeight) || (0 >= pAvi->nWidth)) return E_FAIL; WCHAR szFmt[64]; if (LoadString(m_hInst, IDS_DIMENSIONS_FMT, szFmt, ARRAYSIZE(szFmt))) { DWORD_PTR args[2]; args[0] = (DWORD_PTR)pAvi->nWidth; args[1] = (DWORD_PTR)pAvi->nHeight; WCHAR szBuffer[64]; FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, szFmt, 0, 0, szBuffer, ARRAYSIZE(szBuffer), (va_list*)args); hr = SHStrDup(szBuffer, &pVar->pwszVal); if (SUCCEEDED(hr)) pVar->vt = VT_LPWSTR; else pVar->vt = VT_EMPTY; } else hr = E_FAIL; break; default: hr = E_UNEXPECTED; } } else if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation)) { hr = S_OK; switch (pid) { case PIDASI_TIMELENGTH: if (0 >= pAvi->nLength) return E_FAIL; // This value is in milliseconds. // However, we define duration to be in 100ns units, so multiply by 10000. pVar->uhVal.LowPart = pAvi->nLength; pVar->uhVal.HighPart = 0; pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000; pVar->vt = VT_UI8; break; case PIDASI_FORMAT: if (0 == *pAvi->szWaveFormat) return E_FAIL; hr = SHStrDupW(pAvi->szWaveFormat, &pVar->pwszVal); if (SUCCEEDED(hr)) pVar->vt = VT_LPWSTR; else return hr; break; default: hr = E_UNEXPECTED; } } else if (IsEqualGUID(reffmtid, FMTID_VideoSummaryInformation)) { hr = S_OK; switch (pid) { case PIDVSI_FRAME_RATE: if (0 >= pAvi->nFrameRate) return E_FAIL; // Value is in frames/millisecond. pVar->ulVal = pAvi->nFrameRate; pVar->vt = VT_UI4; break; case PIDVSI_DATA_RATE: if (0 >= pAvi->nDataRate) return E_FAIL; // This is in bits or bytes per second. pVar->ulVal = pAvi->nDataRate; pVar->vt = VT_UI4; break; case PIDVSI_SAMPLE_SIZE: if (0 >= pAvi->nBitDepth) return E_FAIL; // bit depth pVar->ulVal = pAvi->nBitDepth; pVar->vt = VT_UI4; break; case PIDVSI_COMPRESSION: if (0 == *pAvi->szCompression) return E_FAIL; hr = SHStrDupW(pAvi->szCompression, &pVar->pwszVal); if (SUCCEEDED(hr)) pVar->vt = VT_LPWSTR; else return hr; break; default: hr = E_UNEXPECTED; } } if (FAILED(hr)) hr = _getWaveAudioProperty(reffmtid, pid, pAvi->pwfx, pVar); return hr; } // declares class CWavPropSetStg : public CMediaPropSetStg { public: CWavPropSetStg(); // IPersist STDMETHODIMP GetClassID(CLSID *pClassID); private: HRESULT _PopulatePropertySet(); HRESULT _PopulateSlowProperties(); BOOL _IsSlowProperty(const COLMAP *pPInfo); }; class CMidiPropSetStg : public CMediaPropSetStg { public: CMidiPropSetStg(); // IPersist STDMETHODIMP GetClassID(CLSID *pClassID); private: HRESULT _PopulatePropertySet(); }; class CAviPropSetStg : public CMediaPropSetStg { public: CAviPropSetStg(); // IPersist STDMETHODIMP GetClassID(CLSID *pClassID); private: HRESULT _PopulatePropertySet(); HRESULT _PopulateSlowProperties(); BOOL _IsSlowProperty(const COLMAP *pPInfo); }; //impls // Wav property set storage CWavPropSetStg::CWavPropSetStg() : CMediaPropSetStg() { _pPropStgInfo = g_rgAVWavPropStgs; _cPropertyStorages = ARRAYSIZE(g_rgAVWavPropStgs); } STDMETHODIMP CWavPropSetStg::GetClassID(CLSID *pClassID) { *pClassID = CLSID_AVWavProperties; return S_OK; } BOOL CWavPropSetStg::_IsSlowProperty(const COLMAP *pPInfo) { return TRUE; // It is slow to get WAV properties. } HRESULT CWavPropSetStg::_PopulateSlowProperties() { if (!_bSlowPropertiesExtracted) { _bSlowPropertiesExtracted = TRUE; WAVEDESC wd = {0}; HRESULT hr = GetWaveInfo(_wszFile, &wd); if (SUCCEEDED(hr)) { CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages); const COLMAP *pPInfo = enumAllProps.Next(); while (pPInfo) { PROPVARIANT var = {0}; if (SUCCEEDED(GetWaveProperty(pPInfo->pscid->fmtid, pPInfo->pscid->pid, &wd, &var))) { _PopulateProperty(pPInfo, &var); PropVariantClear(&var); } pPInfo = enumAllProps.Next(); } } FreeWaveInfo(&wd); _hrSlowProps = hr; } return _hrSlowProps; } HRESULT CWavPropSetStg::_PopulatePropertySet() { if (!_bHasBeenPopulated) { if (_wszFile[0] == 0) { _hrPopulated = STG_E_INVALIDNAME; } else { _hrPopulated = S_OK; } _bHasBeenPopulated = TRUE; } return _hrPopulated; } // midi property set storage CMidiPropSetStg::CMidiPropSetStg() : CMediaPropSetStg() { _pPropStgInfo = g_rgAVMidiPropStgs; _cPropertyStorages = ARRAYSIZE(g_rgAVMidiPropStgs); } STDMETHODIMP CMidiPropSetStg::GetClassID(CLSID *pClassID) { *pClassID = CLSID_AVMidiProperties; return S_OK; } HRESULT CMidiPropSetStg::_PopulatePropertySet() { HRESULT hr = E_FAIL; if (_wszFile[0] == 0) { hr = STG_E_INVALIDNAME; } else if (_bHasBeenPopulated) { hr = _hrPopulated; } else { MIDIDESC md; hr = GetMidiInfo(_wszFile, &md); if (SUCCEEDED(hr)) { CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages); const COLMAP *pPInfo = enumAllProps.Next(); while (pPInfo) { PROPVARIANT var = {0}; if (SUCCEEDED(GetMidiProperty(pPInfo->pscid->fmtid, pPInfo->pscid->pid, &md, &var))) { _PopulateProperty(pPInfo, &var); } pPInfo = enumAllProps.Next(); } } } return hr; } // avi property set storage CAviPropSetStg::CAviPropSetStg() : CMediaPropSetStg() { _pPropStgInfo = g_rgAVAviPropStgs; _cPropertyStorages = ARRAYSIZE(g_rgAVAviPropStgs); } STDMETHODIMP CAviPropSetStg::GetClassID(CLSID *pClassID) { *pClassID = CLSID_AVAviProperties; return S_OK; } HRESULT CAviPropSetStg::_PopulateSlowProperties() { if (!_bSlowPropertiesExtracted) { _bSlowPropertiesExtracted = TRUE; AVIDESC ad = {0}; HRESULT hr = GetAviInfo(_wszFile, &ad); if (SUCCEEDED(hr)) { CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages); const COLMAP *pPInfo = enumAllProps.Next(); while (pPInfo) { PROPVARIANT var = {0}; if (SUCCEEDED(GetAviProperty(pPInfo->pscid->fmtid, pPInfo->pscid->pid, &ad, &var))) { _PopulateProperty(pPInfo, &var); } pPInfo = enumAllProps.Next(); } } FreeAviInfo(&ad); _hrSlowProps = hr; } return _hrSlowProps; } BOOL CAviPropSetStg::_IsSlowProperty(const COLMAP *pPInfo) { return TRUE; // It is slow to get AVI properties. } HRESULT CAviPropSetStg::_PopulatePropertySet() { if (!_bHasBeenPopulated) { if (_wszFile[0] == 0) { _hrPopulated = STG_E_INVALIDNAME; } else { _hrPopulated = S_OK; } _bHasBeenPopulated = TRUE; } return _hrPopulated; } // Creates STDAPI CWavPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { HRESULT hr; CWavPropSetStg *pPropSetStg = new CWavPropSetStg(); if (pPropSetStg) { hr = pPropSetStg->Init(); if (SUCCEEDED(hr)) { hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); } pPropSetStg->Release(); } else { *ppunk = NULL; hr = E_OUTOFMEMORY; } return hr; } STDAPI CMidiPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { HRESULT hr; CMidiPropSetStg *pPropSetStg = new CMidiPropSetStg(); if (pPropSetStg) { hr = pPropSetStg->Init(); if (SUCCEEDED(hr)) { hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); } pPropSetStg->Release(); } else { *ppunk = NULL; hr = E_OUTOFMEMORY; } return hr; } STDAPI CAviPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { HRESULT hr; CAviPropSetStg *pPropSetStg = new CAviPropSetStg(); if (pPropSetStg) { hr = pPropSetStg->Init(); if (SUCCEEDED(hr)) { hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); } pPropSetStg->Release(); } else { *ppunk = NULL; hr = E_OUTOFMEMORY; } return hr; }