Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1261 lines
34 KiB

  1. #include "pch.h"
  2. #include "thisdll.h"
  3. #include "ids.h"
  4. #include "MediaProp.h"
  5. #define MAX_DESCRIPTOR 256
  6. #include <mmsystem.h>
  7. #include <vfw.h>
  8. #include <msacm.h>
  9. // Wav file stuff
  10. typedef struct
  11. {
  12. DWORD dwSize;
  13. LONG nLength; // milliseconds
  14. TCHAR szWaveFormat[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
  15. PWAVEFORMATEX pwfx;
  16. } WAVEDESC;
  17. STDMETHODIMP GetWaveInfo(IN LPCTSTR pszFile, OUT WAVEDESC *p);
  18. STDMETHODIMP GetWaveProperty(IN REFFMTID reffmtid, IN PROPID propid, IN const WAVEDESC* pWave, OUT PROPVARIANT* pVar);
  19. const COLMAP* c_rgAVWavAudioProps[] =
  20. {
  21. {&g_CM_Duration},
  22. {&g_CM_Bitrate},
  23. {&g_CM_SampleRate},
  24. {&g_CM_SampleSize},
  25. {&g_CM_ChannelCount},
  26. {&g_CM_Format},
  27. };
  28. const PROPSET_INFO g_rgAVWavPropStgs[] =
  29. {
  30. { PSGUID_AUDIO, c_rgAVWavAudioProps, ARRAYSIZE(c_rgAVWavAudioProps)},
  31. };
  32. // Wav files
  33. // Avi file stuff
  34. typedef struct
  35. {
  36. DWORD dwSize;
  37. LONG nLength; // milliseconds
  38. LONG nWidth; // pixels
  39. LONG nHeight; // pixels
  40. LONG nBitDepth;
  41. LONG cFrames;
  42. LONG nFrameRate; // frames/1000 seconds
  43. LONG nDataRate; // bytes/second
  44. TCHAR szCompression[MAX_DESCRIPTOR];
  45. TCHAR szStreamName[MAX_DESCRIPTOR];
  46. TCHAR szWaveFormat[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
  47. PWAVEFORMATEX pwfx;
  48. } AVIDESC;
  49. STDMETHODIMP GetAviInfo(IN LPCTSTR pszFile, OUT AVIDESC *p);
  50. STDMETHODIMP GetAviProperty(IN REFFMTID reffmtid, IN PROPID propid, IN const AVIDESC* pAvi, OUT PROPVARIANT* pVar);
  51. const COLMAP* c_rgAVAviAudioProps[] =
  52. {
  53. {&g_CM_Duration},
  54. {&g_CM_SampleSize},
  55. {&g_CM_Bitrate},
  56. {&g_CM_Format},
  57. };
  58. const COLMAP* c_rgAVAviImageProps[] =
  59. {
  60. {&g_CM_Width},
  61. {&g_CM_Height},
  62. {&g_CM_Dimensions},
  63. };
  64. const COLMAP* c_rgAVAviVideoProps[] =
  65. {
  66. {&g_CM_FrameCount},
  67. {&g_CM_FrameRate},
  68. {&g_CM_Compression},
  69. {&g_CM_BitrateV},
  70. {&g_CM_SampleSizeV},
  71. };
  72. const COLMAP* c_rgAVAviSummaryProps[] =
  73. {
  74. {&g_CM_Title},
  75. };
  76. const PROPSET_INFO g_rgAVAviPropStgs[] =
  77. {
  78. { PSGUID_AUDIO, c_rgAVAviAudioProps, ARRAYSIZE(c_rgAVAviAudioProps)},
  79. { PSGUID_SUMMARYINFORMATION, c_rgAVAviSummaryProps, ARRAYSIZE(c_rgAVAviSummaryProps)},
  80. { PSGUID_VIDEO, c_rgAVAviVideoProps, ARRAYSIZE(c_rgAVAviVideoProps)},
  81. { PSGUID_IMAGESUMMARYINFORMATION, c_rgAVAviImageProps, ARRAYSIZE(c_rgAVAviImageProps)},
  82. };
  83. // avi
  84. // Midi file stuff
  85. // Note: Midi files are REALLLLLY slow.
  86. typedef struct
  87. {
  88. LONG nLength;
  89. TCHAR szMidiCopyright[MAX_DESCRIPTOR];
  90. TCHAR szMidiSequenceName[MAX_DESCRIPTOR];
  91. } MIDIDESC;
  92. STDMETHODIMP GetMidiInfo(IN LPCTSTR pszFile, OUT MIDIDESC *p);
  93. STDMETHODIMP GetMidiProperty(IN REFFMTID reffmtid, IN PROPID propid, IN const MIDIDESC* pMidi, OUT PROPVARIANT* pVar);
  94. const COLMAP* c_rgAVMidiAudioProps[] =
  95. {
  96. {&g_CM_Duration},
  97. };
  98. const COLMAP* c_rgAVMidiSummaryProps[] =
  99. {
  100. {&g_CM_Title}, // SequenceName
  101. };
  102. const PROPSET_INFO g_rgAVMidiPropStgs[] =
  103. {
  104. { PSGUID_AUDIO, c_rgAVMidiAudioProps, ARRAYSIZE(c_rgAVMidiAudioProps)},
  105. { PSGUID_SUMMARYINFORMATION, c_rgAVMidiSummaryProps, ARRAYSIZE(c_rgAVMidiSummaryProps)},
  106. };
  107. // Midi
  108. #define FOURCC_INFO mmioFOURCC('I','N','F','O')
  109. #define FOURCC_DISP mmioFOURCC('D','I','S','P')
  110. #define FOURCC_IARL mmioFOURCC('I','A','R','L')
  111. #define FOURCC_IART mmioFOURCC('I','A','R','T')
  112. #define FOURCC_ICMS mmioFOURCC('I','C','M','S')
  113. #define FOURCC_ICMT mmioFOURCC('I','C','M','T')
  114. #define FOURCC_ICOP mmioFOURCC('I','C','O','P')
  115. #define FOURCC_ICRD mmioFOURCC('I','C','R','D')
  116. #define FOURCC_ICRP mmioFOURCC('I','C','R','P')
  117. #define FOURCC_IDIM mmioFOURCC('I','D','I','M')
  118. #define FOURCC_IDPI mmioFOURCC('I','D','P','I')
  119. #define FOURCC_IENG mmioFOURCC('I','E','N','G')
  120. #define FOURCC_IGNR mmioFOURCC('I','G','N','R')
  121. #define FOURCC_IKEY mmioFOURCC('I','K','E','Y')
  122. #define FOURCC_ILGT mmioFOURCC('I','L','G','T')
  123. #define FOURCC_IMED mmioFOURCC('I','M','E','D')
  124. #define FOURCC_INAM mmioFOURCC('I','N','A','M')
  125. #define FOURCC_IPLT mmioFOURCC('I','P','L','T')
  126. #define FOURCC_IPRD mmioFOURCC('I','P','R','D')
  127. #define FOURCC_ISBJ mmioFOURCC('I','S','B','J')
  128. #define FOURCC_ISFT mmioFOURCC('I','S','F','T')
  129. #define FOURCC_ISHP mmioFOURCC('I','S','H','P')
  130. #define FOURCC_ISRC mmioFOURCC('I','S','R','C')
  131. #define FOURCC_ISRF mmioFOURCC('I','S','R','F')
  132. #define FOURCC_ITCH mmioFOURCC('I','T','C','H')
  133. #define FOURCC_VIDC mmioFOURCC('V','I','D','C')
  134. #define mmioWAVE mmioFOURCC('W','A','V','E')
  135. #define mmioFMT mmioFOURCC('f','m','t',' ')
  136. #define mmioDATA mmioFOURCC('d','a','t','a')
  137. #define MAXNUMSTREAMS 50
  138. //#define _MIDI_PROPERTY_SUPPORT_
  139. STDMETHODIMP GetMidiInfo(LPCTSTR pszFile, MIDIDESC *pmidi)
  140. {
  141. #ifdef _MIDI_PROPERTY_SUPPORT_
  142. MCI_OPEN_PARMS mciOpen; /* Structure for MCI_OPEN command */
  143. DWORD dwFlags;
  144. DWORD dw;
  145. MCIDEVICEID wDevID;
  146. MCI_STATUS_PARMS mciStatus;
  147. MCI_SET_PARMS mciSet; /* Structure for MCI_SET command */
  148. MCI_INFO_PARMS mciInfo;
  149. /* Open a file with an explicitly specified device */
  150. mciOpen.lpstrDeviceType = TEXT("sequencer");
  151. mciOpen.lpstrElementName = pszFile;
  152. dwFlags = MCI_WAIT | MCI_OPEN_ELEMENT | MCI_OPEN_TYPE;
  153. dw = mciSendCommand((MCIDEVICEID)0, MCI_OPEN, dwFlags,(DWORD_PTR)(LPVOID)&mciOpen);
  154. if (dw)
  155. return E_FAIL;
  156. wDevID = mciOpen.wDeviceID;
  157. mciSet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
  158. dw = mciSendCommand(wDevID, MCI_SET, MCI_SET_TIME_FORMAT,
  159. (DWORD_PTR) (LPVOID) &mciSet);
  160. if (dw)
  161. {
  162. mciSendCommand(wDevID, MCI_CLOSE, 0L, (DWORD)0);
  163. return E_FAIL;
  164. }
  165. mciStatus.dwItem = MCI_STATUS_LENGTH;
  166. dw = mciSendCommand(wDevID, MCI_STATUS, MCI_STATUS_ITEM,
  167. (DWORD_PTR) (LPTSTR) &mciStatus);
  168. if (dw)
  169. pmidi->nLength = 0;
  170. else
  171. pmidi->nLength = (UINT)mciStatus.dwReturn;
  172. mciInfo.dwCallback = 0;
  173. mciInfo.lpstrReturn = pmidi->szMidiCopyright;
  174. mciInfo.dwRetSize = sizeof(pmidi->szMidiCopyright);
  175. *mciInfo.lpstrReturn = 0;
  176. mciSendCommand(wDevID, MCI_INFO, MCI_INFO_COPYRIGHT, (DWORD_PTR)(LPVOID)&mciInfo);
  177. mciInfo.lpstrReturn = pmidi->szMidiCopyright;
  178. mciInfo.dwRetSize = sizeof(pmidi->szMidiSequenceName);
  179. *mciInfo.lpstrReturn = 0;
  180. mciSendCommand(wDevID, MCI_INFO, MCI_INFO_NAME, (DWORD_PTR)(LPVOID)&mciInfo);
  181. mciSendCommand(wDevID, MCI_CLOSE, 0L, (DWORD)0);
  182. return S_OK;
  183. #else _MIDI_PROPERTY_SUPPORT_
  184. return E_FAIL;
  185. #endif _MIDI_PROPERTY_SUPPORT_
  186. }
  187. STDMETHODIMP GetMidiProperty(
  188. IN REFFMTID reffmtid,
  189. IN PROPID pid,
  190. IN const MIDIDESC* pMidi,
  191. OUT PROPVARIANT* pVar)
  192. {
  193. HRESULT hr = S_OK;
  194. if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation))
  195. {
  196. hr = S_OK;
  197. switch (pid)
  198. {
  199. case PIDASI_TIMELENGTH:
  200. if (0 >= pMidi->nLength)
  201. return E_FAIL;
  202. // This value is in milliseconds.
  203. // However, we define duration to be in 100ns units, so multiply by 10000.
  204. pVar->uhVal.LowPart = pMidi->nLength;
  205. pVar->uhVal.HighPart = 0;
  206. pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000;
  207. pVar->vt = VT_UI8;
  208. break;
  209. }
  210. }
  211. return hr;
  212. }
  213. HRESULT ReadWaveHeader(HMMIO hmmio, WAVEDESC *pwd)
  214. {
  215. BOOL bRet = FALSE;
  216. MMCKINFO mmckRIFF;
  217. MMCKINFO mmck;
  218. DWORD dwFormatSize;
  219. MMRESULT wError;
  220. ZeroMemory(pwd, sizeof(*pwd));
  221. mmckRIFF.fccType = mmioWAVE;
  222. if ((wError = mmioDescend(hmmio, &mmckRIFF, NULL, MMIO_FINDRIFF)))
  223. {
  224. return E_FAIL;
  225. }
  226. mmck.ckid = mmioFMT;
  227. if ((wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK)))
  228. {
  229. return E_FAIL;
  230. }
  231. if (mmck.cksize < sizeof(WAVEFORMAT))
  232. {
  233. return E_FAIL;
  234. }
  235. dwFormatSize = mmck.cksize;
  236. if (dwFormatSize <= 0x0000ffff) // (anything with a huge header is probably a corrupt file, so fail)
  237. {
  238. pwd->pwfx = (PWAVEFORMATEX)new BYTE[dwFormatSize];
  239. if (pwd->pwfx)
  240. {
  241. if ((DWORD)mmioRead(hmmio, (HPSTR)pwd->pwfx, mmck.cksize) != mmck.cksize)
  242. {
  243. goto retErr;
  244. }
  245. if (pwd->pwfx->wFormatTag == WAVE_FORMAT_PCM)
  246. {
  247. if (dwFormatSize < sizeof(PCMWAVEFORMAT))
  248. {
  249. goto retErr;
  250. }
  251. }
  252. else if ((dwFormatSize < sizeof(WAVEFORMATEX)) ||
  253. (dwFormatSize < sizeof(WAVEFORMATEX) + pwd->pwfx->cbSize))
  254. {
  255. goto retErr;
  256. }
  257. if ((wError = mmioAscend(hmmio, &mmck, 0)))
  258. {
  259. goto retErr;
  260. }
  261. mmck.ckid = mmioDATA;
  262. if ((wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK)))
  263. {
  264. goto retErr;
  265. }
  266. pwd->dwSize = mmck.cksize;
  267. return S_OK;
  268. }
  269. }
  270. retErr:
  271. if (pwd->pwfx)
  272. {
  273. delete [] (LPBYTE)pwd->pwfx;
  274. pwd->pwfx = NULL;
  275. }
  276. return E_FAIL;
  277. }
  278. // Retrieves text representation of format tag
  279. STDMETHODIMP GetWaveFormatTag(PWAVEFORMATEX pwfx, LPTSTR pszTag, IN ULONG cchTag)
  280. {
  281. ASSERT(pwfx);
  282. ASSERT(pszTag);
  283. ASSERT(cchTag);
  284. ACMFORMATTAGDETAILS aftd;
  285. ZeroMemory(&aftd, sizeof(aftd));
  286. aftd.cbStruct = sizeof(ACMFORMATTAGDETAILSW);
  287. aftd.dwFormatTag = pwfx->wFormatTag;
  288. if (0 == acmFormatTagDetails(NULL, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG))
  289. {
  290. // copy to output - ok if truncated.
  291. StringCchCopy(pszTag, cchTag, aftd.szFormatTag);
  292. return S_OK;
  293. }
  294. return E_FAIL;
  295. }
  296. STDMETHODIMP GetWaveInfo(IN LPCTSTR pszFile, OUT WAVEDESC *p)
  297. {
  298. HMMIO hmmio;
  299. if (NULL == (hmmio = mmioOpen((LPTSTR)pszFile, NULL, MMIO_ALLOCBUF | MMIO_READ)))
  300. return E_FAIL;
  301. HRESULT hr = ReadWaveHeader(hmmio, p);
  302. mmioClose(hmmio, 0);
  303. if (SUCCEEDED(hr) && p->pwfx)
  304. {
  305. // Retrieve text representation of format tag
  306. GetWaveFormatTag(p->pwfx, p->szWaveFormat, ARRAYSIZE(p->szWaveFormat));
  307. }
  308. return hr;
  309. }
  310. STDMETHODIMP FreeWaveInfo(IN OUT WAVEDESC *p)
  311. {
  312. if (p->pwfx)
  313. {
  314. delete [] p->pwfx;
  315. p->pwfx = NULL;
  316. }
  317. return S_OK;
  318. }
  319. STDMETHODIMP _getWaveAudioProperty(
  320. IN REFFMTID reffmtid,
  321. IN PROPID pid,
  322. IN const PWAVEFORMATEX pwfx,
  323. OUT PROPVARIANT* pVar)
  324. {
  325. HRESULT hr = E_UNEXPECTED;
  326. TCHAR szBuf[MAX_DESCRIPTOR],
  327. szFmt[MAX_DESCRIPTOR];
  328. PropVariantInit(pVar);
  329. *szBuf = *szFmt = 0;
  330. if (pwfx && IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation))
  331. {
  332. hr = S_OK;
  333. switch (pid)
  334. {
  335. case PIDASI_AVG_DATA_RATE:
  336. if (0 >= pwfx->nAvgBytesPerSec)
  337. return E_FAIL;
  338. // Convert into bits per sec.
  339. pVar->ulVal = pwfx->nAvgBytesPerSec * 8;
  340. pVar->vt = VT_UI4;
  341. break;
  342. case PIDASI_SAMPLE_RATE:
  343. if (0 >= pwfx->nSamplesPerSec)
  344. return E_FAIL;
  345. // Samples per second (/1000 to get kHz)
  346. pVar->ulVal = pwfx->nSamplesPerSec;
  347. pVar->vt = VT_UI4;
  348. break;
  349. case PIDASI_SAMPLE_SIZE:
  350. if (0 >= pwfx->wBitsPerSample)
  351. return E_FAIL;
  352. // Bits per sample.
  353. pVar->ulVal = pwfx->wBitsPerSample;
  354. pVar->vt = VT_UI4;
  355. break;
  356. case PIDASI_CHANNEL_COUNT:
  357. {
  358. if (0 >= pwfx->nChannels)
  359. return E_FAIL;
  360. pVar->ulVal = pwfx->nChannels;
  361. pVar->vt = VT_UI4;
  362. break;
  363. }
  364. default:
  365. return E_UNEXPECTED;
  366. }
  367. }
  368. return hr;
  369. }
  370. STDMETHODIMP GetWaveProperty(
  371. IN REFFMTID reffmtid,
  372. IN PROPID pid,
  373. IN const WAVEDESC* pWave,
  374. OUT PROPVARIANT* pVar)
  375. {
  376. HRESULT hr = E_FAIL;
  377. TCHAR szBuf[MAX_DESCRIPTOR],
  378. szFmt[MAX_DESCRIPTOR];
  379. PropVariantInit(pVar);
  380. *szBuf = *szFmt = 0;
  381. if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation))
  382. {
  383. hr = S_OK;
  384. switch (pid)
  385. {
  386. case PIDASI_FORMAT:
  387. if (0 == *pWave->szWaveFormat)
  388. return E_FAIL;
  389. hr = SHStrDupW(pWave->szWaveFormat, &pVar->pwszVal);
  390. if (SUCCEEDED(hr))
  391. pVar->vt = VT_LPWSTR;
  392. else
  393. return hr;
  394. break;
  395. // ISSUE: nLength is never filled in in GetWaveInfo, so this will always be zero.
  396. case PIDASI_TIMELENGTH:
  397. if (0 >= pWave->nLength)
  398. return E_FAIL;
  399. // This value is in milliseconds.
  400. // However, we define duration to be in 100ns units, so multiply by 10000.
  401. pVar->uhVal.LowPart = pWave->nLength;
  402. pVar->uhVal.HighPart = 0;
  403. pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000;
  404. pVar->vt = VT_UI8;
  405. break;
  406. default:
  407. hr = E_UNEXPECTED;
  408. }
  409. }
  410. if (FAILED(hr))
  411. hr = _getWaveAudioProperty(reffmtid, pid, pWave->pwfx, pVar);
  412. return hr;
  413. }
  414. STDMETHODIMP ReadAviStreams(LPCTSTR pszFile, DWORD dwFileSize, AVIDESC *pAvi)
  415. {
  416. HRESULT hr;
  417. PAVIFILE pfile;
  418. PAVISTREAM pavi;
  419. PAVISTREAM rgpavis[MAXNUMSTREAMS]; // the current streams
  420. AVISTREAMINFO avsi;
  421. LONG timeStart; // cached start, end, length
  422. LONG timeEnd;
  423. int cpavi;
  424. int i;
  425. hr = AVIFileOpen(&pfile, pszFile, 0, 0L);
  426. if (FAILED(hr))
  427. return hr;
  428. for (i = 0; i <= MAXNUMSTREAMS; i++)
  429. {
  430. if (AVIFileGetStream(pfile, &pavi, 0L, i) != AVIERR_OK)
  431. break;
  432. if (i == MAXNUMSTREAMS)
  433. {
  434. AVIStreamRelease(pavi);
  435. //DPF("Exceeded maximum number of streams");
  436. break;
  437. }
  438. #pragma prefast(suppress:201, we already broke out when i == MAXNUMSTREAMS (PREfast bug 546))
  439. rgpavis[i] = pavi;
  440. }
  441. //
  442. // Couldn't get any streams out of this file
  443. //
  444. if (i == 0)
  445. {
  446. //DPF("Unable to open any streams in %s", pszFile);
  447. if (pfile)
  448. AVIFileRelease(pfile);
  449. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  450. }
  451. cpavi = i;
  452. //
  453. // Start with bogus times
  454. //
  455. timeStart = 0x7FFFFFFF;
  456. timeEnd = 0;
  457. //
  458. // Walk through and init all streams loaded
  459. //
  460. for (i = 0; i < cpavi; i++)
  461. {
  462. AVIStreamInfo(rgpavis[i], &avsi, sizeof(avsi));
  463. switch (avsi.fccType)
  464. {
  465. case streamtypeVIDEO:
  466. {
  467. LONG cbFormat;
  468. LPBYTE lpFormat;
  469. ICINFO icInfo;
  470. HIC hic;
  471. DWORD dwTimeLen;
  472. if (AVIStreamFormatSize(rgpavis[i], 0, &cbFormat) == AVIERR_OK)
  473. {
  474. dwTimeLen = AVIStreamEndTime(rgpavis[i]) - AVIStreamStartTime(rgpavis[i]);
  475. pAvi->cFrames = avsi.dwLength;
  476. pAvi->nFrameRate = MulDiv(avsi.dwLength, 1000000, dwTimeLen);
  477. pAvi->nDataRate = MulDiv(dwFileSize, 1000000, dwTimeLen)/1024;
  478. pAvi->nWidth = avsi.rcFrame.right - avsi.rcFrame.left;
  479. pAvi->nHeight = avsi.rcFrame.bottom - avsi.rcFrame.top;
  480. // ok if truncated.
  481. StringCchCopy(pAvi->szStreamName, ARRAYSIZE(pAvi->szStreamName), avsi.szName);
  482. // Retrieve raster info (compression, bit depth).
  483. lpFormat = new BYTE[cbFormat];
  484. if (lpFormat)
  485. {
  486. if (AVIStreamReadFormat(rgpavis[i], 0, lpFormat, &cbFormat) == AVIERR_OK)
  487. {
  488. hic = (HIC)ICLocate(FOURCC_VIDC, avsi.fccHandler, (BITMAPINFOHEADER*)lpFormat,
  489. NULL, (WORD)ICMODE_DECOMPRESS);
  490. if (hic || ((LPBITMAPINFOHEADER)lpFormat)->biCompression == 0)
  491. {
  492. if (((LPBITMAPINFOHEADER)lpFormat)->biCompression)
  493. {
  494. ICGetInfo(hic, &icInfo, sizeof(ICINFO));
  495. ICClose(hic);
  496. // ok if truncated.
  497. StringCchCopy(pAvi->szCompression, ARRAYSIZE(pAvi->szCompression), icInfo.szName);
  498. }
  499. else
  500. {
  501. LoadString(m_hInst, IDS_AVI_UNCOMPRESSED, pAvi->szCompression, ARRAYSIZE(pAvi->szCompression));
  502. }
  503. pAvi->nBitDepth = ((LPBITMAPINFOHEADER)lpFormat)->biBitCount;
  504. }
  505. }
  506. delete [] lpFormat;
  507. }
  508. }
  509. else
  510. hr = E_OUTOFMEMORY;
  511. break;
  512. }
  513. case streamtypeAUDIO:
  514. {
  515. LONG cbFormat;
  516. if (AVIStreamFormatSize(rgpavis[i], 0, &cbFormat) == AVIERR_OK)
  517. {
  518. pAvi->pwfx = (PWAVEFORMATEX) new BYTE[cbFormat];
  519. if (pAvi->pwfx)
  520. {
  521. ZeroMemory(pAvi->pwfx, cbFormat);
  522. if (AVIStreamReadFormat(rgpavis[i], 0, pAvi->pwfx, &cbFormat) == 0)
  523. {
  524. GetWaveFormatTag(pAvi->pwfx, pAvi->szWaveFormat, ARRAYSIZE(pAvi->szWaveFormat));
  525. }
  526. }
  527. }
  528. break;
  529. }
  530. default:
  531. break;
  532. }
  533. //
  534. // We're finding the earliest and latest start and end points for
  535. // our scrollbar.
  536. //
  537. timeStart = min(timeStart, AVIStreamStartTime(rgpavis[i]));
  538. timeEnd = max(timeEnd, AVIStreamEndTime(rgpavis[i]));
  539. }
  540. pAvi->nLength = (UINT)(timeEnd - timeStart);
  541. for (i = 0; i < cpavi; i++)
  542. {
  543. AVIStreamRelease(rgpavis[i]);
  544. }
  545. AVIFileRelease(pfile);
  546. return S_OK;
  547. }
  548. // Because some AVI programs don't export the correct headers, retrieving AVI info will take
  549. // an extremly long time on some files, we need to verify that the headers are available
  550. // before we call AVIFileOpen
  551. BOOL _ValidAviHeaderInfo(LPCTSTR pszFile)
  552. {
  553. BOOL fRet = FALSE; // Assume it is bad
  554. HMMIO hmmio = mmioOpen((LPWSTR)pszFile, NULL, MMIO_READ);
  555. if (hmmio)
  556. {
  557. MMCKINFO ckRIFF;
  558. if (mmioDescend(hmmio, &ckRIFF, NULL, 0) == 0)
  559. {
  560. if ((ckRIFF.ckid == FOURCC_RIFF) && (ckRIFF.fccType == formtypeAVI))
  561. {
  562. MMCKINFO ckLIST;
  563. ckLIST.fccType = listtypeAVIHEADER;
  564. if (mmioDescend(hmmio, &ckLIST, &ckRIFF, MMIO_FINDLIST) == 0)
  565. {
  566. ckRIFF.ckid = ckidAVIMAINHDR;
  567. if (mmioDescend(hmmio, &ckRIFF, &ckLIST, MMIO_FINDCHUNK) == 0)
  568. {
  569. MainAVIHeader Hdr;
  570. ULONG cb = min(sizeof Hdr, ckRIFF.cksize);
  571. if (mmioRead(hmmio, (HPSTR)&Hdr, cb) == cb)
  572. {
  573. fRet = Hdr.dwFlags & AVIF_HASINDEX;
  574. }
  575. }
  576. }
  577. }
  578. }
  579. mmioClose(hmmio, 0);
  580. }
  581. return fRet;
  582. }
  583. STDMETHODIMP GetAviInfo(LPCTSTR pszFile, AVIDESC *pavi)
  584. {
  585. HRESULT hr = E_UNEXPECTED;
  586. if (_ValidAviHeaderInfo(pszFile))
  587. {
  588. // Retrieve the file size
  589. HANDLE hFile = CreateFile(pszFile,
  590. GENERIC_READ,
  591. FILE_SHARE_READ,NULL,
  592. OPEN_EXISTING,
  593. FILE_ATTRIBUTE_NORMAL,
  594. NULL);
  595. if (INVALID_HANDLE_VALUE == hFile)
  596. {
  597. DWORD dwRet = GetLastError();
  598. return ERROR_SUCCESS != dwRet ? HRESULT_FROM_WIN32(dwRet) : E_UNEXPECTED;
  599. }
  600. DWORD dwFileSize = GetFileSize((HANDLE)hFile, NULL);
  601. CloseHandle(hFile);
  602. AVIFileInit();
  603. hr = ReadAviStreams(pszFile, dwFileSize, pavi);
  604. AVIFileExit();
  605. }
  606. return hr;
  607. }
  608. STDMETHODIMP FreeAviInfo(IN OUT AVIDESC *p)
  609. {
  610. if (p->pwfx)
  611. {
  612. delete [] p->pwfx;
  613. p->pwfx = NULL;
  614. }
  615. return S_OK;
  616. }
  617. STDMETHODIMP GetAviProperty(
  618. IN REFFMTID reffmtid,
  619. IN PROPID pid,
  620. IN const AVIDESC* pAvi,
  621. OUT PROPVARIANT* pVar)
  622. {
  623. HRESULT hr = E_UNEXPECTED;
  624. TCHAR szBuf[MAX_DESCRIPTOR],
  625. szFmt[MAX_DESCRIPTOR];
  626. PropVariantInit(pVar);
  627. *szBuf = *szFmt = 0;
  628. if (IsEqualGUID(reffmtid, FMTID_SummaryInformation))
  629. {
  630. hr = S_OK;
  631. switch (pid)
  632. {
  633. case PIDSI_TITLE:
  634. if (0 == *pAvi->szStreamName)
  635. return E_FAIL;
  636. hr = SHStrDupW(pAvi->szStreamName, &pVar->pwszVal);
  637. if (SUCCEEDED(hr))
  638. pVar->vt = VT_LPWSTR;
  639. else
  640. return hr;
  641. default:
  642. hr = E_UNEXPECTED;
  643. }
  644. }
  645. else if (IsEqualGUID(reffmtid, FMTID_ImageSummaryInformation))
  646. {
  647. hr = S_OK;
  648. switch (pid)
  649. {
  650. case PIDISI_CX:
  651. if (0 >= pAvi->nWidth)
  652. return E_FAIL;
  653. pVar->ulVal = pAvi->nWidth;
  654. pVar->vt = VT_UI4;
  655. break;
  656. case PIDISI_CY:
  657. if (0 >= pAvi->nHeight)
  658. return E_FAIL;
  659. pVar->ulVal = pAvi->nHeight;
  660. pVar->vt = VT_UI4;
  661. break;
  662. case PIDISI_FRAME_COUNT:
  663. if (0 >= pAvi->cFrames)
  664. return E_FAIL;
  665. pVar->ulVal = pAvi->cFrames;
  666. pVar->vt = VT_UI4;
  667. break;
  668. case PIDISI_DIMENSIONS:
  669. if ((0 >= pAvi->nHeight) || (0 >= pAvi->nWidth))
  670. return E_FAIL;
  671. WCHAR szFmt[64];
  672. if (LoadString(m_hInst, IDS_DIMENSIONS_FMT, szFmt, ARRAYSIZE(szFmt)))
  673. {
  674. DWORD_PTR args[2];
  675. args[0] = (DWORD_PTR)pAvi->nWidth;
  676. args[1] = (DWORD_PTR)pAvi->nHeight;
  677. WCHAR szBuffer[64];
  678. FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  679. szFmt, 0, 0, szBuffer, ARRAYSIZE(szBuffer), (va_list*)args);
  680. hr = SHStrDup(szBuffer, &pVar->pwszVal);
  681. if (SUCCEEDED(hr))
  682. pVar->vt = VT_LPWSTR;
  683. else
  684. pVar->vt = VT_EMPTY;
  685. }
  686. else
  687. hr = E_FAIL;
  688. break;
  689. default:
  690. hr = E_UNEXPECTED;
  691. }
  692. }
  693. else if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation))
  694. {
  695. hr = S_OK;
  696. switch (pid)
  697. {
  698. case PIDASI_TIMELENGTH:
  699. if (0 >= pAvi->nLength)
  700. return E_FAIL;
  701. // This value is in milliseconds.
  702. // However, we define duration to be in 100ns units, so multiply by 10000.
  703. pVar->uhVal.LowPart = pAvi->nLength;
  704. pVar->uhVal.HighPart = 0;
  705. pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000;
  706. pVar->vt = VT_UI8;
  707. break;
  708. case PIDASI_FORMAT:
  709. if (0 == *pAvi->szWaveFormat)
  710. return E_FAIL;
  711. hr = SHStrDupW(pAvi->szWaveFormat, &pVar->pwszVal);
  712. if (SUCCEEDED(hr))
  713. pVar->vt = VT_LPWSTR;
  714. else
  715. return hr;
  716. break;
  717. default:
  718. hr = E_UNEXPECTED;
  719. }
  720. }
  721. else if (IsEqualGUID(reffmtid, FMTID_VideoSummaryInformation))
  722. {
  723. hr = S_OK;
  724. switch (pid)
  725. {
  726. case PIDVSI_FRAME_RATE:
  727. if (0 >= pAvi->nFrameRate)
  728. return E_FAIL;
  729. // Value is in frames/millisecond.
  730. pVar->ulVal = pAvi->nFrameRate;
  731. pVar->vt = VT_UI4;
  732. break;
  733. case PIDVSI_DATA_RATE:
  734. if (0 >= pAvi->nDataRate)
  735. return E_FAIL;
  736. // This is in bits or bytes per second.
  737. pVar->ulVal = pAvi->nDataRate;
  738. pVar->vt = VT_UI4;
  739. break;
  740. case PIDVSI_SAMPLE_SIZE:
  741. if (0 >= pAvi->nBitDepth)
  742. return E_FAIL;
  743. // bit depth
  744. pVar->ulVal = pAvi->nBitDepth;
  745. pVar->vt = VT_UI4;
  746. break;
  747. case PIDVSI_COMPRESSION:
  748. if (0 == *pAvi->szCompression)
  749. return E_FAIL;
  750. hr = SHStrDupW(pAvi->szCompression, &pVar->pwszVal);
  751. if (SUCCEEDED(hr))
  752. pVar->vt = VT_LPWSTR;
  753. else
  754. return hr;
  755. break;
  756. default:
  757. hr = E_UNEXPECTED;
  758. }
  759. }
  760. if (FAILED(hr))
  761. hr = _getWaveAudioProperty(reffmtid, pid, pAvi->pwfx, pVar);
  762. return hr;
  763. }
  764. // declares
  765. class CWavPropSetStg : public CMediaPropSetStg
  766. {
  767. public:
  768. CWavPropSetStg();
  769. // IPersist
  770. STDMETHODIMP GetClassID(CLSID *pClassID);
  771. private:
  772. HRESULT _PopulatePropertySet();
  773. HRESULT _PopulateSlowProperties();
  774. BOOL _IsSlowProperty(const COLMAP *pPInfo);
  775. };
  776. class CMidiPropSetStg : public CMediaPropSetStg
  777. {
  778. public:
  779. CMidiPropSetStg();
  780. // IPersist
  781. STDMETHODIMP GetClassID(CLSID *pClassID);
  782. private:
  783. HRESULT _PopulatePropertySet();
  784. };
  785. class CAviPropSetStg : public CMediaPropSetStg
  786. {
  787. public:
  788. CAviPropSetStg();
  789. // IPersist
  790. STDMETHODIMP GetClassID(CLSID *pClassID);
  791. private:
  792. HRESULT _PopulatePropertySet();
  793. HRESULT _PopulateSlowProperties();
  794. BOOL _IsSlowProperty(const COLMAP *pPInfo);
  795. };
  796. //impls
  797. // Wav property set storage
  798. CWavPropSetStg::CWavPropSetStg() : CMediaPropSetStg()
  799. {
  800. _pPropStgInfo = g_rgAVWavPropStgs;
  801. _cPropertyStorages = ARRAYSIZE(g_rgAVWavPropStgs);
  802. }
  803. STDMETHODIMP CWavPropSetStg::GetClassID(CLSID *pClassID)
  804. {
  805. *pClassID = CLSID_AVWavProperties;
  806. return S_OK;
  807. }
  808. BOOL CWavPropSetStg::_IsSlowProperty(const COLMAP *pPInfo)
  809. {
  810. return TRUE; // It is slow to get WAV properties.
  811. }
  812. HRESULT CWavPropSetStg::_PopulateSlowProperties()
  813. {
  814. if (!_bSlowPropertiesExtracted)
  815. {
  816. _bSlowPropertiesExtracted = TRUE;
  817. WAVEDESC wd = {0};
  818. HRESULT hr = GetWaveInfo(_wszFile, &wd);
  819. if (SUCCEEDED(hr))
  820. {
  821. CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages);
  822. const COLMAP *pPInfo = enumAllProps.Next();
  823. while (pPInfo)
  824. {
  825. PROPVARIANT var = {0};
  826. if (SUCCEEDED(GetWaveProperty(pPInfo->pscid->fmtid,
  827. pPInfo->pscid->pid,
  828. &wd,
  829. &var)))
  830. {
  831. _PopulateProperty(pPInfo, &var);
  832. PropVariantClear(&var);
  833. }
  834. pPInfo = enumAllProps.Next();
  835. }
  836. }
  837. FreeWaveInfo(&wd);
  838. _hrSlowProps = hr;
  839. }
  840. return _hrSlowProps;
  841. }
  842. HRESULT CWavPropSetStg::_PopulatePropertySet()
  843. {
  844. if (!_bHasBeenPopulated)
  845. {
  846. if (_wszFile[0] == 0)
  847. {
  848. _hrPopulated = STG_E_INVALIDNAME;
  849. }
  850. else
  851. {
  852. _hrPopulated = S_OK;
  853. }
  854. _bHasBeenPopulated = TRUE;
  855. }
  856. return _hrPopulated;
  857. }
  858. // midi property set storage
  859. CMidiPropSetStg::CMidiPropSetStg() : CMediaPropSetStg()
  860. {
  861. _pPropStgInfo = g_rgAVMidiPropStgs;
  862. _cPropertyStorages = ARRAYSIZE(g_rgAVMidiPropStgs);
  863. }
  864. STDMETHODIMP CMidiPropSetStg::GetClassID(CLSID *pClassID)
  865. {
  866. *pClassID = CLSID_AVMidiProperties;
  867. return S_OK;
  868. }
  869. HRESULT CMidiPropSetStg::_PopulatePropertySet()
  870. {
  871. HRESULT hr = E_FAIL;
  872. if (_wszFile[0] == 0)
  873. {
  874. hr = STG_E_INVALIDNAME;
  875. }
  876. else if (_bHasBeenPopulated)
  877. {
  878. hr = _hrPopulated;
  879. }
  880. else
  881. {
  882. MIDIDESC md;
  883. hr = GetMidiInfo(_wszFile, &md);
  884. if (SUCCEEDED(hr))
  885. {
  886. CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages);
  887. const COLMAP *pPInfo = enumAllProps.Next();
  888. while (pPInfo)
  889. {
  890. PROPVARIANT var = {0};
  891. if (SUCCEEDED(GetMidiProperty(pPInfo->pscid->fmtid,
  892. pPInfo->pscid->pid,
  893. &md,
  894. &var)))
  895. {
  896. _PopulateProperty(pPInfo, &var);
  897. }
  898. pPInfo = enumAllProps.Next();
  899. }
  900. }
  901. }
  902. return hr;
  903. }
  904. // avi property set storage
  905. CAviPropSetStg::CAviPropSetStg() : CMediaPropSetStg()
  906. {
  907. _pPropStgInfo = g_rgAVAviPropStgs;
  908. _cPropertyStorages = ARRAYSIZE(g_rgAVAviPropStgs);
  909. }
  910. STDMETHODIMP CAviPropSetStg::GetClassID(CLSID *pClassID)
  911. {
  912. *pClassID = CLSID_AVAviProperties;
  913. return S_OK;
  914. }
  915. HRESULT CAviPropSetStg::_PopulateSlowProperties()
  916. {
  917. if (!_bSlowPropertiesExtracted)
  918. {
  919. _bSlowPropertiesExtracted = TRUE;
  920. AVIDESC ad = {0};
  921. HRESULT hr = GetAviInfo(_wszFile, &ad);
  922. if (SUCCEEDED(hr))
  923. {
  924. CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages);
  925. const COLMAP *pPInfo = enumAllProps.Next();
  926. while (pPInfo)
  927. {
  928. PROPVARIANT var = {0};
  929. if (SUCCEEDED(GetAviProperty(pPInfo->pscid->fmtid,
  930. pPInfo->pscid->pid,
  931. &ad,
  932. &var)))
  933. {
  934. _PopulateProperty(pPInfo, &var);
  935. }
  936. pPInfo = enumAllProps.Next();
  937. }
  938. }
  939. FreeAviInfo(&ad);
  940. _hrSlowProps = hr;
  941. }
  942. return _hrSlowProps;
  943. }
  944. BOOL CAviPropSetStg::_IsSlowProperty(const COLMAP *pPInfo)
  945. {
  946. return TRUE; // It is slow to get AVI properties.
  947. }
  948. HRESULT CAviPropSetStg::_PopulatePropertySet()
  949. {
  950. if (!_bHasBeenPopulated)
  951. {
  952. if (_wszFile[0] == 0)
  953. {
  954. _hrPopulated = STG_E_INVALIDNAME;
  955. }
  956. else
  957. {
  958. _hrPopulated = S_OK;
  959. }
  960. _bHasBeenPopulated = TRUE;
  961. }
  962. return _hrPopulated;
  963. }
  964. // Creates
  965. STDAPI CWavPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  966. {
  967. HRESULT hr;
  968. CWavPropSetStg *pPropSetStg = new CWavPropSetStg();
  969. if (pPropSetStg)
  970. {
  971. hr = pPropSetStg->Init();
  972. if (SUCCEEDED(hr))
  973. {
  974. hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  975. }
  976. pPropSetStg->Release();
  977. }
  978. else
  979. {
  980. *ppunk = NULL;
  981. hr = E_OUTOFMEMORY;
  982. }
  983. return hr;
  984. }
  985. STDAPI CMidiPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  986. {
  987. HRESULT hr;
  988. CMidiPropSetStg *pPropSetStg = new CMidiPropSetStg();
  989. if (pPropSetStg)
  990. {
  991. hr = pPropSetStg->Init();
  992. if (SUCCEEDED(hr))
  993. {
  994. hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  995. }
  996. pPropSetStg->Release();
  997. }
  998. else
  999. {
  1000. *ppunk = NULL;
  1001. hr = E_OUTOFMEMORY;
  1002. }
  1003. return hr;
  1004. }
  1005. STDAPI CAviPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  1006. {
  1007. HRESULT hr;
  1008. CAviPropSetStg *pPropSetStg = new CAviPropSetStg();
  1009. if (pPropSetStg)
  1010. {
  1011. hr = pPropSetStg->Init();
  1012. if (SUCCEEDED(hr))
  1013. {
  1014. hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  1015. }
  1016. pPropSetStg->Release();
  1017. }
  1018. else
  1019. {
  1020. *ppunk = NULL;
  1021. hr = E_OUTOFMEMORY;
  1022. }
  1023. return hr;
  1024. }