Source code of Windows XP (NT5)
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.

1233 lines
31 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. static HRESULT ReadWaveHeader(HMMIO hmmio, WAVEDESC *pwd)
  214. {
  215. BOOL bRet = FALSE;
  216. MMCKINFO mmckRIFF;
  217. MMCKINFO mmck;
  218. WORD wFormatSize;
  219. MMRESULT wError;
  220. ZeroMemory(pwd, sizeof(*pwd));
  221. mmckRIFF.fccType = mmioWAVE;
  222. if ((wError = mmioDescend(hmmio, &mmckRIFF, NULL, MMIO_FINDRIFF)))
  223. {
  224. return FALSE;
  225. }
  226. mmck.ckid = mmioFMT;
  227. if ((wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK)))
  228. {
  229. return FALSE;
  230. }
  231. if (mmck.cksize < sizeof(WAVEFORMAT))
  232. {
  233. return FALSE;
  234. }
  235. wFormatSize = (WORD)mmck.cksize;
  236. if (NULL != (pwd->pwfx = (PWAVEFORMATEX)new BYTE[wFormatSize]))
  237. {
  238. if ((DWORD)mmioRead(hmmio, (HPSTR)pwd->pwfx, mmck.cksize) != mmck.cksize)
  239. {
  240. goto retErr;
  241. }
  242. if (pwd->pwfx->wFormatTag == WAVE_FORMAT_PCM)
  243. {
  244. if (wFormatSize < sizeof(PCMWAVEFORMAT))
  245. {
  246. goto retErr;
  247. }
  248. }
  249. else if ((wFormatSize < sizeof(WAVEFORMATEX)) ||
  250. (wFormatSize < sizeof(WAVEFORMATEX) + pwd->pwfx->cbSize))
  251. {
  252. goto retErr;
  253. }
  254. if ((wError = mmioAscend(hmmio, &mmck, 0)))
  255. {
  256. goto retErr;
  257. }
  258. mmck.ckid = mmioDATA;
  259. if ((wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK)))
  260. {
  261. goto retErr;
  262. }
  263. pwd->dwSize = mmck.cksize;
  264. return S_OK;
  265. }
  266. retErr:
  267. delete [] (LPBYTE)pwd->pwfx;
  268. return E_FAIL;
  269. }
  270. // Retrieves text representation of format tag
  271. STDMETHODIMP GetWaveFormatTag(PWAVEFORMATEX pwfx, LPTSTR pszTag, IN ULONG cchTag)
  272. {
  273. ASSERT(pwfx);
  274. ASSERT(pszTag);
  275. ASSERT(cchTag);
  276. ACMFORMATTAGDETAILS aftd;
  277. ZeroMemory(&aftd, sizeof(aftd));
  278. aftd.cbStruct = sizeof(ACMFORMATTAGDETAILSW);
  279. aftd.dwFormatTag = pwfx->wFormatTag;
  280. if (0 == acmFormatTagDetails(NULL, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG))
  281. {
  282. // copy to output.
  283. lstrcpyn(pszTag, aftd.szFormatTag, cchTag);
  284. return S_OK;
  285. }
  286. return E_FAIL;
  287. }
  288. STDMETHODIMP GetWaveInfo(IN LPCTSTR pszFile, OUT WAVEDESC *p)
  289. {
  290. HMMIO hmmio;
  291. if (NULL == (hmmio = mmioOpen((LPTSTR)pszFile, NULL, MMIO_ALLOCBUF | MMIO_READ)))
  292. return E_FAIL;
  293. HRESULT hr = ReadWaveHeader(hmmio, p);
  294. mmioClose(hmmio, 0);
  295. if (SUCCEEDED(hr) && p->pwfx)
  296. {
  297. // Retrieve text representation of format tag
  298. GetWaveFormatTag(p->pwfx, p->szWaveFormat, ARRAYSIZE(p->szWaveFormat));
  299. }
  300. return hr;
  301. }
  302. STDMETHODIMP FreeWaveInfo(IN OUT WAVEDESC *p)
  303. {
  304. if (!(p && sizeof(*p) == p->dwSize) && p->pwfx)
  305. {
  306. delete [] p->pwfx;
  307. p->pwfx = NULL;
  308. }
  309. return S_OK;
  310. }
  311. STDMETHODIMP _getWaveAudioProperty(
  312. IN REFFMTID reffmtid,
  313. IN PROPID pid,
  314. IN const PWAVEFORMATEX pwfx,
  315. OUT PROPVARIANT* pVar)
  316. {
  317. HRESULT hr = E_UNEXPECTED;
  318. TCHAR szBuf[MAX_DESCRIPTOR],
  319. szFmt[MAX_DESCRIPTOR];
  320. PropVariantInit(pVar);
  321. *szBuf = *szFmt = 0;
  322. if (pwfx && IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation))
  323. {
  324. hr = S_OK;
  325. switch (pid)
  326. {
  327. case PIDASI_AVG_DATA_RATE:
  328. if (0 >= pwfx->nAvgBytesPerSec)
  329. return E_FAIL;
  330. // Convert into bits per sec.
  331. pVar->ulVal = pwfx->nAvgBytesPerSec * 8;
  332. pVar->vt = VT_UI4;
  333. break;
  334. case PIDASI_SAMPLE_RATE:
  335. if (0 >= pwfx->nSamplesPerSec)
  336. return E_FAIL;
  337. // Samples per second (/1000 to get kHz)
  338. pVar->ulVal = pwfx->nSamplesPerSec;
  339. pVar->vt = VT_UI4;
  340. break;
  341. case PIDASI_SAMPLE_SIZE:
  342. if (0 >= pwfx->wBitsPerSample)
  343. return E_FAIL;
  344. // Bits per sample.
  345. pVar->ulVal = pwfx->wBitsPerSample;
  346. pVar->vt = VT_UI4;
  347. break;
  348. case PIDASI_CHANNEL_COUNT:
  349. {
  350. if (0 >= pwfx->nChannels)
  351. return E_FAIL;
  352. pVar->ulVal = pwfx->nChannels;
  353. pVar->vt = VT_UI4;
  354. break;
  355. }
  356. default:
  357. return E_UNEXPECTED;
  358. }
  359. }
  360. return hr;
  361. }
  362. STDMETHODIMP GetWaveProperty(
  363. IN REFFMTID reffmtid,
  364. IN PROPID pid,
  365. IN const WAVEDESC* pWave,
  366. OUT PROPVARIANT* pVar)
  367. {
  368. HRESULT hr = E_FAIL;
  369. TCHAR szBuf[MAX_DESCRIPTOR],
  370. szFmt[MAX_DESCRIPTOR];
  371. PropVariantInit(pVar);
  372. *szBuf = *szFmt = 0;
  373. if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation))
  374. {
  375. hr = S_OK;
  376. switch (pid)
  377. {
  378. case PIDASI_FORMAT:
  379. if (0 == *pWave->szWaveFormat)
  380. return E_FAIL;
  381. hr = SHStrDupW(pWave->szWaveFormat, &pVar->pwszVal);
  382. if (SUCCEEDED(hr))
  383. pVar->vt = VT_LPWSTR;
  384. else
  385. return hr;
  386. break;
  387. // ISSUE: nLength is never filled in in GetWaveInfo, so this will always be zero.
  388. case PIDASI_TIMELENGTH:
  389. if (0 >= pWave->nLength)
  390. return E_FAIL;
  391. // This value is in milliseconds.
  392. // However, we define duration to be in 100ns units, so multiply by 10000.
  393. pVar->uhVal.LowPart = pWave->nLength;
  394. pVar->uhVal.HighPart = 0;
  395. pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000;
  396. pVar->vt = VT_UI8;
  397. break;
  398. default:
  399. hr = E_UNEXPECTED;
  400. }
  401. }
  402. if (FAILED(hr))
  403. hr = _getWaveAudioProperty(reffmtid, pid, pWave->pwfx, pVar);
  404. return hr;
  405. }
  406. STDMETHODIMP ReadAviStreams(LPCTSTR pszFile, DWORD dwFileSize, AVIDESC *pAvi)
  407. {
  408. HRESULT hr;
  409. PAVIFILE pfile;
  410. PAVISTREAM pavi;
  411. PAVISTREAM rgpavis[MAXNUMSTREAMS]; // the current streams
  412. AVISTREAMINFO avsi;
  413. LONG timeStart; // cached start, end, length
  414. LONG timeEnd;
  415. int cpavi;
  416. int i;
  417. if (FAILED((hr = AVIFileOpen(&pfile, pszFile, 0, 0L))))
  418. return hr;
  419. for (i = 0; i <= MAXNUMSTREAMS; i++)
  420. {
  421. if (AVIFileGetStream(pfile, &pavi, 0L, i) != AVIERR_OK)
  422. break;
  423. if (i == MAXNUMSTREAMS)
  424. {
  425. AVIStreamRelease(pavi);
  426. //DPF("Exceeded maximum number of streams");
  427. break;
  428. }
  429. rgpavis[i] = pavi;
  430. }
  431. //
  432. // Couldn't get any streams out of this file
  433. //
  434. if (i == 0)
  435. {
  436. //DPF("Unable to open any streams in %s", pszFile);
  437. if (pfile)
  438. AVIFileRelease(pfile);
  439. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  440. }
  441. cpavi = i;
  442. //
  443. // Start with bogus times
  444. //
  445. timeStart = 0x7FFFFFFF;
  446. timeEnd = 0;
  447. //
  448. // Walk through and init all streams loaded
  449. //
  450. for (i = 0; i < cpavi; i++)
  451. {
  452. AVIStreamInfo(rgpavis[i], &avsi, sizeof(avsi));
  453. switch (avsi.fccType)
  454. {
  455. case streamtypeVIDEO:
  456. {
  457. LONG cbFormat;
  458. LPBYTE lpFormat;
  459. ICINFO icInfo;
  460. HIC hic;
  461. DWORD dwTimeLen;
  462. AVIStreamFormatSize(rgpavis[i], 0, &cbFormat);
  463. dwTimeLen = AVIStreamEndTime(rgpavis[i]) - AVIStreamStartTime(rgpavis[i]);
  464. pAvi->cFrames = avsi.dwLength;
  465. pAvi->nFrameRate = MulDiv(avsi.dwLength, 1000000, dwTimeLen);
  466. pAvi->nDataRate = MulDiv(dwFileSize, 1000000, dwTimeLen)/1024;
  467. pAvi->nWidth = avsi.rcFrame.right - avsi.rcFrame.left;
  468. pAvi->nHeight = avsi.rcFrame.bottom - avsi.rcFrame.top;
  469. lstrcpyn(pAvi->szStreamName, avsi.szName, ARRAYSIZE(pAvi->szStreamName));
  470. // Retrieve raster info (compression, bit depth).
  471. lpFormat = new BYTE[cbFormat];
  472. if (lpFormat)
  473. {
  474. AVIStreamReadFormat(rgpavis[i], 0, lpFormat, &cbFormat);
  475. hic = (HIC)ICLocate(FOURCC_VIDC, avsi.fccHandler, (BITMAPINFOHEADER*)lpFormat,
  476. NULL, (WORD)ICMODE_DECOMPRESS);
  477. if (hic || ((LPBITMAPINFOHEADER)lpFormat)->biCompression == 0)
  478. {
  479. if (((LPBITMAPINFOHEADER)lpFormat)->biCompression)
  480. {
  481. ICGetInfo(hic, &icInfo, sizeof(ICINFO));
  482. ICClose(hic);
  483. lstrcpy(pAvi->szCompression, icInfo.szName);
  484. }
  485. else
  486. {
  487. LoadString(m_hInst, IDS_AVI_UNCOMPRESSED, pAvi->szCompression, ARRAYSIZE(pAvi->szCompression));
  488. }
  489. pAvi->nBitDepth = ((LPBITMAPINFOHEADER)lpFormat)->biBitCount;
  490. }
  491. delete [] lpFormat;
  492. }
  493. else
  494. hr = E_OUTOFMEMORY;
  495. break;
  496. }
  497. case streamtypeAUDIO:
  498. {
  499. LONG cbFormat;
  500. AVIStreamFormatSize(rgpavis[i], 0, &cbFormat);
  501. if ((pAvi->pwfx = (PWAVEFORMATEX) new BYTE[cbFormat]) != NULL)
  502. {
  503. ZeroMemory(pAvi->pwfx, cbFormat);
  504. if (SUCCEEDED(AVIStreamReadFormat(rgpavis[i], 0, pAvi->pwfx, &cbFormat)))
  505. GetWaveFormatTag(pAvi->pwfx, pAvi->szWaveFormat, ARRAYSIZE(pAvi->szWaveFormat));
  506. }
  507. break;
  508. }
  509. default:
  510. break;
  511. }
  512. //
  513. // We're finding the earliest and latest start and end points for
  514. // our scrollbar.
  515. //
  516. timeStart = min(timeStart, AVIStreamStartTime(rgpavis[i]));
  517. timeEnd = max(timeEnd, AVIStreamEndTime(rgpavis[i]));
  518. }
  519. pAvi->nLength = (UINT)(timeEnd - timeStart);
  520. for (i = 0; i < cpavi; i++)
  521. {
  522. AVIStreamRelease(rgpavis[i]);
  523. }
  524. AVIFileRelease(pfile);
  525. return S_OK;
  526. }
  527. // Because some AVI programs don't export the correct headers, retrieving AVI info will take
  528. // an extremly long time on some files, we need to verify that the headers are available
  529. // before we call AVIFileOpen
  530. BOOL _ValidAviHeaderInfo(LPCTSTR pszFile)
  531. {
  532. BOOL fRet = FALSE; // Assume it is bad
  533. HMMIO hmmio = mmioOpen((LPWSTR)pszFile, NULL, MMIO_READ);
  534. if (hmmio)
  535. {
  536. MMCKINFO ckRIFF;
  537. if (mmioDescend(hmmio, &ckRIFF, NULL, 0) == 0)
  538. {
  539. if ((ckRIFF.ckid == FOURCC_RIFF) && (ckRIFF.fccType == formtypeAVI))
  540. {
  541. MMCKINFO ckLIST;
  542. ckLIST.fccType = listtypeAVIHEADER;
  543. if (mmioDescend(hmmio, &ckLIST, &ckRIFF, MMIO_FINDLIST) == 0)
  544. {
  545. ckRIFF.ckid = ckidAVIMAINHDR;
  546. if (mmioDescend(hmmio, &ckRIFF, &ckLIST, MMIO_FINDCHUNK) == 0)
  547. {
  548. MainAVIHeader Hdr;
  549. ULONG cb = min(sizeof Hdr, ckRIFF.cksize);
  550. if (mmioRead(hmmio, (HPSTR)&Hdr, cb) == cb)
  551. {
  552. fRet = Hdr.dwFlags & AVIF_HASINDEX;
  553. }
  554. }
  555. }
  556. }
  557. }
  558. mmioClose(hmmio, 0);
  559. }
  560. return fRet;
  561. }
  562. STDMETHODIMP GetAviInfo(LPCTSTR pszFile, AVIDESC *pavi)
  563. {
  564. HRESULT hr = E_UNEXPECTED;
  565. if (_ValidAviHeaderInfo(pszFile))
  566. {
  567. // Retrieve the file size
  568. HANDLE hFile = CreateFile(pszFile,
  569. GENERIC_READ,
  570. FILE_SHARE_READ,NULL,
  571. OPEN_EXISTING,
  572. FILE_ATTRIBUTE_NORMAL,
  573. NULL);
  574. if (INVALID_HANDLE_VALUE == hFile)
  575. {
  576. DWORD dwRet = GetLastError();
  577. return ERROR_SUCCESS != dwRet ? HRESULT_FROM_WIN32(dwRet) : E_UNEXPECTED;
  578. }
  579. DWORD dwFileSize = GetFileSize((HANDLE)hFile, NULL);
  580. CloseHandle(hFile);
  581. AVIFileInit();
  582. hr = ReadAviStreams(pszFile, dwFileSize, pavi);
  583. AVIFileExit();
  584. }
  585. return hr;
  586. }
  587. STDMETHODIMP FreeAviInfo(IN OUT AVIDESC *p)
  588. {
  589. if (!(p && sizeof(*p) == p->dwSize) && p->pwfx)
  590. {
  591. delete [] p->pwfx;
  592. p->pwfx = NULL;
  593. }
  594. return S_OK;
  595. }
  596. STDMETHODIMP GetAviProperty(
  597. IN REFFMTID reffmtid,
  598. IN PROPID pid,
  599. IN const AVIDESC* pAvi,
  600. OUT PROPVARIANT* pVar)
  601. {
  602. HRESULT hr = E_UNEXPECTED;
  603. TCHAR szBuf[MAX_DESCRIPTOR],
  604. szFmt[MAX_DESCRIPTOR];
  605. PropVariantInit(pVar);
  606. *szBuf = *szFmt = 0;
  607. if (IsEqualGUID(reffmtid, FMTID_SummaryInformation))
  608. {
  609. hr = S_OK;
  610. switch (pid)
  611. {
  612. case PIDSI_TITLE:
  613. if (0 == *pAvi->szStreamName)
  614. return E_FAIL;
  615. hr = SHStrDupW(pAvi->szStreamName, &pVar->pwszVal);
  616. if (SUCCEEDED(hr))
  617. pVar->vt = VT_LPWSTR;
  618. else
  619. return hr;
  620. default:
  621. hr = E_UNEXPECTED;
  622. }
  623. }
  624. else if (IsEqualGUID(reffmtid, FMTID_ImageSummaryInformation))
  625. {
  626. hr = S_OK;
  627. switch (pid)
  628. {
  629. case PIDISI_CX:
  630. if (0 >= pAvi->nWidth)
  631. return E_FAIL;
  632. pVar->ulVal = pAvi->nWidth;
  633. pVar->vt = VT_UI4;
  634. break;
  635. case PIDISI_CY:
  636. if (0 >= pAvi->nHeight)
  637. return E_FAIL;
  638. pVar->ulVal = pAvi->nHeight;
  639. pVar->vt = VT_UI4;
  640. break;
  641. case PIDISI_FRAME_COUNT:
  642. if (0 >= pAvi->cFrames)
  643. return E_FAIL;
  644. pVar->ulVal = pAvi->cFrames;
  645. pVar->vt = VT_UI4;
  646. break;
  647. case PIDISI_DIMENSIONS:
  648. if ((0 >= pAvi->nHeight) || (0 >= pAvi->nWidth))
  649. return E_FAIL;
  650. WCHAR szFmt[64];
  651. if (LoadString(m_hInst, IDS_DIMENSIONS_FMT, szFmt, ARRAYSIZE(szFmt)))
  652. {
  653. DWORD_PTR args[2];
  654. args[0] = (DWORD_PTR)pAvi->nWidth;
  655. args[1] = (DWORD_PTR)pAvi->nHeight;
  656. WCHAR szBuffer[64];
  657. FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  658. szFmt, 0, 0, szBuffer, ARRAYSIZE(szBuffer), (va_list*)args);
  659. hr = SHStrDup(szBuffer, &pVar->pwszVal);
  660. if (SUCCEEDED(hr))
  661. pVar->vt = VT_LPWSTR;
  662. else
  663. pVar->vt = VT_EMPTY;
  664. }
  665. else
  666. hr = E_FAIL;
  667. break;
  668. default:
  669. hr = E_UNEXPECTED;
  670. }
  671. }
  672. else if (IsEqualGUID(reffmtid, FMTID_AudioSummaryInformation))
  673. {
  674. hr = S_OK;
  675. switch (pid)
  676. {
  677. case PIDASI_TIMELENGTH:
  678. if (0 >= pAvi->nLength)
  679. return E_FAIL;
  680. // This value is in milliseconds.
  681. // However, we define duration to be in 100ns units, so multiply by 10000.
  682. pVar->uhVal.LowPart = pAvi->nLength;
  683. pVar->uhVal.HighPart = 0;
  684. pVar->uhVal.QuadPart = pVar->uhVal.QuadPart * 10000;
  685. pVar->vt = VT_UI8;
  686. break;
  687. case PIDASI_FORMAT:
  688. if (0 == *pAvi->szWaveFormat)
  689. return E_FAIL;
  690. hr = SHStrDupW(pAvi->szWaveFormat, &pVar->pwszVal);
  691. if (SUCCEEDED(hr))
  692. pVar->vt = VT_LPWSTR;
  693. else
  694. return hr;
  695. break;
  696. default:
  697. hr = E_UNEXPECTED;
  698. }
  699. }
  700. else if (IsEqualGUID(reffmtid, FMTID_VideoSummaryInformation))
  701. {
  702. hr = S_OK;
  703. switch (pid)
  704. {
  705. case PIDVSI_FRAME_RATE:
  706. if (0 >= pAvi->nFrameRate)
  707. return E_FAIL;
  708. // Value is in frames/millisecond.
  709. pVar->ulVal = pAvi->nFrameRate;
  710. pVar->vt = VT_UI4;
  711. break;
  712. case PIDVSI_DATA_RATE:
  713. if (0 >= pAvi->nDataRate)
  714. return E_FAIL;
  715. // This is in bits or bytes per second.
  716. pVar->ulVal = pAvi->nDataRate;
  717. pVar->vt = VT_UI4;
  718. break;
  719. case PIDVSI_SAMPLE_SIZE:
  720. if (0 >= pAvi->nBitDepth)
  721. return E_FAIL;
  722. // bit depth
  723. pVar->ulVal = pAvi->nBitDepth;
  724. pVar->vt = VT_UI4;
  725. break;
  726. case PIDVSI_COMPRESSION:
  727. if (0 == *pAvi->szCompression)
  728. return E_FAIL;
  729. hr = SHStrDupW(pAvi->szCompression, &pVar->pwszVal);
  730. if (SUCCEEDED(hr))
  731. pVar->vt = VT_LPWSTR;
  732. else
  733. return hr;
  734. break;
  735. default:
  736. hr = E_UNEXPECTED;
  737. }
  738. }
  739. if (FAILED(hr))
  740. hr = _getWaveAudioProperty(reffmtid, pid, pAvi->pwfx, pVar);
  741. return hr;
  742. }
  743. // declares
  744. class CWavPropSetStg : public CMediaPropSetStg
  745. {
  746. public:
  747. // IPersist
  748. STDMETHODIMP GetClassID(CLSID *pClassID);
  749. private:
  750. HRESULT _PopulatePropertySet();
  751. HRESULT _PopulateSlowProperties();
  752. BOOL _IsSlowProperty(const COLMAP *pPInfo);
  753. };
  754. class CMidiPropSetStg : public CMediaPropSetStg
  755. {
  756. public:
  757. // IPersist
  758. STDMETHODIMP GetClassID(CLSID *pClassID);
  759. private:
  760. HRESULT _PopulatePropertySet();
  761. };
  762. class CAviPropSetStg : public CMediaPropSetStg
  763. {
  764. public:
  765. // IPersist
  766. STDMETHODIMP GetClassID(CLSID *pClassID);
  767. private:
  768. HRESULT _PopulatePropertySet();
  769. HRESULT _PopulateSlowProperties();
  770. BOOL _IsSlowProperty(const COLMAP *pPInfo);
  771. };
  772. //impls
  773. // Wav property set storage
  774. CWavPropSetStg::CWavPropSetStg() : CMediaPropSetStg()
  775. {
  776. _pPropStgInfo = g_rgAVWavPropStgs;
  777. _cPropertyStorages = ARRAYSIZE(g_rgAVWavPropStgs);
  778. }
  779. STDMETHODIMP CWavPropSetStg::GetClassID(CLSID *pClassID)
  780. {
  781. *pClassID = CLSID_AVWavProperties;
  782. return S_OK;
  783. }
  784. BOOL CWavPropSetStg::_IsSlowProperty(const COLMAP *pPInfo)
  785. {
  786. return TRUE; // It is slow to get WAV properties.
  787. }
  788. HRESULT CWavPropSetStg::_PopulateSlowProperties()
  789. {
  790. if (!_bSlowPropertiesExtracted)
  791. {
  792. _bSlowPropertiesExtracted = TRUE;
  793. WAVEDESC wd = {0};
  794. HRESULT hr = GetWaveInfo(_wszFile, &wd);
  795. if (SUCCEEDED(hr))
  796. {
  797. CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages);
  798. const COLMAP *pPInfo = enumAllProps.Next();
  799. while (pPInfo)
  800. {
  801. PROPVARIANT var = {0};
  802. if (SUCCEEDED(GetWaveProperty(pPInfo->pscid->fmtid,
  803. pPInfo->pscid->pid,
  804. &wd,
  805. &var)))
  806. {
  807. _PopulateProperty(pPInfo, &var);
  808. PropVariantClear(&var);
  809. }
  810. pPInfo = enumAllProps.Next();
  811. }
  812. }
  813. _hrSlowProps = hr;
  814. }
  815. return _hrSlowProps;
  816. }
  817. HRESULT CWavPropSetStg::_PopulatePropertySet()
  818. {
  819. if (!_bHasBeenPopulated)
  820. {
  821. if (_wszFile[0] == 0)
  822. {
  823. _hrPopulated = STG_E_INVALIDNAME;
  824. }
  825. else
  826. {
  827. _hrPopulated = S_OK;
  828. }
  829. _bHasBeenPopulated = TRUE;
  830. }
  831. return _hrPopulated;
  832. }
  833. // midi property set storage
  834. CMidiPropSetStg::CMidiPropSetStg() : CMediaPropSetStg()
  835. {
  836. _pPropStgInfo = g_rgAVMidiPropStgs;
  837. _cPropertyStorages = ARRAYSIZE(g_rgAVMidiPropStgs);
  838. }
  839. STDMETHODIMP CMidiPropSetStg::GetClassID(CLSID *pClassID)
  840. {
  841. *pClassID = CLSID_AVMidiProperties;
  842. return S_OK;
  843. }
  844. HRESULT CMidiPropSetStg::_PopulatePropertySet()
  845. {
  846. HRESULT hr = E_FAIL;
  847. if (_wszFile[0] == 0)
  848. {
  849. hr = STG_E_INVALIDNAME;
  850. }
  851. else if (_bHasBeenPopulated)
  852. {
  853. hr = _hrPopulated;
  854. }
  855. else
  856. {
  857. MIDIDESC md;
  858. hr = GetMidiInfo(_wszFile, &md);
  859. if (SUCCEEDED(hr))
  860. {
  861. CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages);
  862. const COLMAP *pPInfo = enumAllProps.Next();
  863. while (pPInfo)
  864. {
  865. PROPVARIANT var = {0};
  866. if (SUCCEEDED(GetMidiProperty(pPInfo->pscid->fmtid,
  867. pPInfo->pscid->pid,
  868. &md,
  869. &var)))
  870. {
  871. _PopulateProperty(pPInfo, &var);
  872. }
  873. pPInfo = enumAllProps.Next();
  874. }
  875. }
  876. }
  877. return hr;
  878. }
  879. // avi property set storage
  880. CAviPropSetStg::CAviPropSetStg() : CMediaPropSetStg()
  881. {
  882. _pPropStgInfo = g_rgAVAviPropStgs;
  883. _cPropertyStorages = ARRAYSIZE(g_rgAVAviPropStgs);
  884. }
  885. STDMETHODIMP CAviPropSetStg::GetClassID(CLSID *pClassID)
  886. {
  887. *pClassID = CLSID_AVAviProperties;
  888. return S_OK;
  889. }
  890. HRESULT CAviPropSetStg::_PopulateSlowProperties()
  891. {
  892. if (!_bSlowPropertiesExtracted)
  893. {
  894. _bSlowPropertiesExtracted = TRUE;
  895. AVIDESC ad = {0};
  896. HRESULT hr = GetAviInfo(_wszFile, &ad);
  897. if (SUCCEEDED(hr))
  898. {
  899. CEnumAllProps enumAllProps(_pPropStgInfo, _cPropertyStorages);
  900. const COLMAP *pPInfo = enumAllProps.Next();
  901. while (pPInfo)
  902. {
  903. PROPVARIANT var = {0};
  904. if (SUCCEEDED(GetAviProperty(pPInfo->pscid->fmtid,
  905. pPInfo->pscid->pid,
  906. &ad,
  907. &var)))
  908. {
  909. _PopulateProperty(pPInfo, &var);
  910. }
  911. pPInfo = enumAllProps.Next();
  912. }
  913. }
  914. _hrSlowProps = hr;
  915. }
  916. return _hrSlowProps;
  917. }
  918. BOOL CAviPropSetStg::_IsSlowProperty(const COLMAP *pPInfo)
  919. {
  920. return TRUE; // It is slow to get AVI properties.
  921. }
  922. HRESULT CAviPropSetStg::_PopulatePropertySet()
  923. {
  924. if (!_bHasBeenPopulated)
  925. {
  926. if (_wszFile[0] == 0)
  927. {
  928. _hrPopulated = STG_E_INVALIDNAME;
  929. }
  930. else
  931. {
  932. _hrPopulated = S_OK;
  933. }
  934. _bHasBeenPopulated = TRUE;
  935. }
  936. return _hrPopulated;
  937. }
  938. // Creates
  939. STDAPI CWavPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  940. {
  941. HRESULT hr;
  942. CWavPropSetStg *pPropSetStg = new CWavPropSetStg();
  943. if (pPropSetStg)
  944. {
  945. hr = pPropSetStg->Init();
  946. if (SUCCEEDED(hr))
  947. {
  948. hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  949. }
  950. pPropSetStg->Release();
  951. }
  952. else
  953. {
  954. *ppunk = NULL;
  955. hr = E_OUTOFMEMORY;
  956. }
  957. return hr;
  958. }
  959. STDAPI CMidiPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  960. {
  961. HRESULT hr;
  962. CMidiPropSetStg *pPropSetStg = new CMidiPropSetStg();
  963. if (pPropSetStg)
  964. {
  965. hr = pPropSetStg->Init();
  966. if (SUCCEEDED(hr))
  967. {
  968. hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  969. }
  970. pPropSetStg->Release();
  971. }
  972. else
  973. {
  974. *ppunk = NULL;
  975. hr = E_OUTOFMEMORY;
  976. }
  977. return hr;
  978. }
  979. STDAPI CAviPropSetStg_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  980. {
  981. HRESULT hr;
  982. CAviPropSetStg *pPropSetStg = new CAviPropSetStg();
  983. if (pPropSetStg)
  984. {
  985. hr = pPropSetStg->Init();
  986. if (SUCCEEDED(hr))
  987. {
  988. hr = pPropSetStg->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  989. }
  990. pPropSetStg->Release();
  991. }
  992. else
  993. {
  994. *ppunk = NULL;
  995. hr = E_OUTOFMEMORY;
  996. }
  997. return hr;
  998. }