windows-nt/Source/XPSP1/NT/shell/ext/media/otherpss.cpp
2020-09-26 16:20:57 +08:00

1234 lines
31 KiB
C++

#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;
}
static HRESULT ReadWaveHeader(HMMIO hmmio, WAVEDESC *pwd)
{
BOOL bRet = FALSE;
MMCKINFO mmckRIFF;
MMCKINFO mmck;
WORD wFormatSize;
MMRESULT wError;
ZeroMemory(pwd, sizeof(*pwd));
mmckRIFF.fccType = mmioWAVE;
if ((wError = mmioDescend(hmmio, &mmckRIFF, NULL, MMIO_FINDRIFF)))
{
return FALSE;
}
mmck.ckid = mmioFMT;
if ((wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK)))
{
return FALSE;
}
if (mmck.cksize < sizeof(WAVEFORMAT))
{
return FALSE;
}
wFormatSize = (WORD)mmck.cksize;
if (NULL != (pwd->pwfx = (PWAVEFORMATEX)new BYTE[wFormatSize]))
{
if ((DWORD)mmioRead(hmmio, (HPSTR)pwd->pwfx, mmck.cksize) != mmck.cksize)
{
goto retErr;
}
if (pwd->pwfx->wFormatTag == WAVE_FORMAT_PCM)
{
if (wFormatSize < sizeof(PCMWAVEFORMAT))
{
goto retErr;
}
}
else if ((wFormatSize < sizeof(WAVEFORMATEX)) ||
(wFormatSize < 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:
delete [] (LPBYTE)pwd->pwfx;
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.
lstrcpyn(pszTag, aftd.szFormatTag, cchTag);
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 && sizeof(*p) == p->dwSize) && 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;
if (FAILED((hr = AVIFileOpen(&pfile, pszFile, 0, 0L))))
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;
}
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;
AVIStreamFormatSize(rgpavis[i], 0, &cbFormat);
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;
lstrcpyn(pAvi->szStreamName, avsi.szName, ARRAYSIZE(pAvi->szStreamName));
// Retrieve raster info (compression, bit depth).
lpFormat = new BYTE[cbFormat];
if (lpFormat)
{
AVIStreamReadFormat(rgpavis[i], 0, lpFormat, &cbFormat);
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);
lstrcpy(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;
AVIStreamFormatSize(rgpavis[i], 0, &cbFormat);
if ((pAvi->pwfx = (PWAVEFORMATEX) new BYTE[cbFormat]) != NULL)
{
ZeroMemory(pAvi->pwfx, cbFormat);
if (SUCCEEDED(AVIStreamReadFormat(rgpavis[i], 0, pAvi->pwfx, &cbFormat)))
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 && sizeof(*p) == p->dwSize) && 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:
// IPersist
STDMETHODIMP GetClassID(CLSID *pClassID);
private:
HRESULT _PopulatePropertySet();
HRESULT _PopulateSlowProperties();
BOOL _IsSlowProperty(const COLMAP *pPInfo);
};
class CMidiPropSetStg : public CMediaPropSetStg
{
public:
// IPersist
STDMETHODIMP GetClassID(CLSID *pClassID);
private:
HRESULT _PopulatePropertySet();
};
class CAviPropSetStg : public CMediaPropSetStg
{
public:
// 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();
}
}
_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();
}
}
_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;
}