|
|
#include "pch.h"
#include "thisdll.h"
#include "ids.h"
#include "MediaProp.h"
#define MAX_DESCRIPTOR 256
#include <mmsystem.h>
#include <vfw.h>
#include <msacm.h>
// 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; }
|