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.

333 lines
8.7 KiB

  1. #include "pch.h"
  2. #include "thisdll.h"
  3. #include "wmwrap.h"
  4. #include <streams.h>
  5. #include <shlobj.h>
  6. #include <QEdit.h>
  7. class CVideoThumbnail : public IExtractImage,
  8. public IPersistFile,
  9. public IServiceProvider
  10. {
  11. public:
  12. CVideoThumbnail();
  13. STDMETHOD (QueryInterface)(REFIID riid, void **ppv);
  14. STDMETHOD_(ULONG, AddRef) ();
  15. STDMETHOD_(ULONG, Release) ();
  16. // IExtractImage
  17. STDMETHOD (GetLocation)(LPWSTR pszPathBuffer, DWORD cch,
  18. DWORD * pdwPriority, const SIZE * prgSize,
  19. DWORD dwRecClrDepth, DWORD *pdwFlags);
  20. STDMETHOD (Extract)(HBITMAP *phBmpThumbnail);
  21. // IPersistFile
  22. STDMETHOD (GetClassID)(CLSID *pClassID);
  23. STDMETHOD (IsDirty)();
  24. STDMETHOD (Load)(LPCOLESTR pszFileName, DWORD dwMode);
  25. STDMETHOD (Save)(LPCOLESTR pszFileName, BOOL fRemember);
  26. STDMETHOD (SaveCompleted)(LPCOLESTR pszFileName);
  27. STDMETHOD (GetCurFile)(LPOLESTR *ppszFileName);
  28. // IServiceProvider
  29. STDMETHOD (QueryService)(REFGUID guidService, REFIID riid, void **ppv);
  30. private:
  31. ~CVideoThumbnail();
  32. HRESULT _InitToVideoStream();
  33. HRESULT _GetThumbnailBits(BITMAPINFO **ppbi);
  34. LONG _cRef;
  35. TCHAR _szPath[MAX_PATH];
  36. IMediaDet *_pmedia;
  37. SIZE _rgSize;
  38. DWORD _dwRecClrDepth;
  39. };
  40. CVideoThumbnail::CVideoThumbnail() : _cRef(1)
  41. {
  42. DllAddRef();
  43. }
  44. CVideoThumbnail::~CVideoThumbnail()
  45. {
  46. if (_pmedia)
  47. {
  48. IUnknown_SetSite(_pmedia, NULL);
  49. _pmedia->Release();
  50. }
  51. DllRelease();
  52. }
  53. HRESULT CVideoThumbnail::QueryInterface(REFIID riid, void **ppv)
  54. {
  55. static const QITAB qit[] = {
  56. QITABENT(CVideoThumbnail, IExtractImage),
  57. QITABENT(CVideoThumbnail, IPersistFile),
  58. QITABENTMULTI(CVideoThumbnail, IPersist, IPersistFile),
  59. QITABENT(CVideoThumbnail, IServiceProvider),
  60. { 0 },
  61. };
  62. return QISearch(this, qit, riid, ppv);
  63. }
  64. STDMETHODIMP_(ULONG) CVideoThumbnail::AddRef()
  65. {
  66. return InterlockedIncrement(&_cRef);
  67. }
  68. STDMETHODIMP_(ULONG) CVideoThumbnail::Release()
  69. {
  70. if (InterlockedDecrement(&_cRef))
  71. return _cRef;
  72. delete this;
  73. return 0;
  74. }
  75. HRESULT CVideoThumbnail::_InitToVideoStream()
  76. {
  77. HRESULT hr = E_FAIL;
  78. if (_pmedia)
  79. {
  80. hr = S_OK;
  81. }
  82. else
  83. {
  84. if (_szPath[0])
  85. {
  86. hr = CoCreateInstance(CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IMediaDet, &_pmedia));
  87. if (SUCCEEDED(hr))
  88. {
  89. // set the site provider on the MediaDet object to
  90. // allowed keyed apps to use ASF decoder
  91. IUnknown_SetSite(_pmedia, SAFECAST(this, IServiceProvider*));
  92. // really this takes a BSTR but since this is inproc this works
  93. hr = _pmedia->put_Filename(_szPath);
  94. if (SUCCEEDED(hr))
  95. {
  96. // now seek to the first video stream so we can get it's bits
  97. long nStreams;
  98. if (SUCCEEDED(_pmedia->get_OutputStreams(&nStreams)))
  99. {
  100. for (long i = 0; i < nStreams; i++)
  101. {
  102. _pmedia->put_CurrentStream(i);
  103. GUID guid = {0};
  104. _pmedia->get_StreamType(&guid);
  105. if (guid == MEDIATYPE_Video)
  106. break;
  107. // else if (guid == MEDIATYPE_Audio)
  108. // BOOL bHasAudio = TRUE;
  109. }
  110. }
  111. }
  112. }
  113. }
  114. }
  115. return hr;
  116. }
  117. HRESULT CVideoThumbnail::_GetThumbnailBits(BITMAPINFO **ppbi)
  118. {
  119. *ppbi = NULL;
  120. HRESULT hr = _InitToVideoStream();
  121. if (SUCCEEDED(hr))
  122. {
  123. long iWidth = _rgSize.cx;
  124. long iHeight = _rgSize.cy;
  125. AM_MEDIA_TYPE mt;
  126. hr = _pmedia->get_StreamMediaType(&mt);
  127. if (SUCCEEDED(hr))
  128. {
  129. if (mt.formattype == FORMAT_VideoInfo)
  130. {
  131. VIDEOINFOHEADER * pvih = (VIDEOINFOHEADER *)mt.pbFormat;
  132. iWidth = pvih->bmiHeader.biWidth;
  133. iHeight = pvih->bmiHeader.biHeight;
  134. }
  135. /*
  136. // REVIEW: Do we have any reason to support these additional types?
  137. else if (mt.formattype == FORMAT_VideoInfo2 || mt.formattype == FORMAT_MPEGVideo)
  138. {
  139. // REVIEW: Does FORMAT_MPEGVideo really start with a VIDEOINFOHEADER2 structure?
  140. VIDEOINFOHEADER2 * pvih = (VIDEOINFOHEADER2 *)mt.pbFormat;
  141. iWidth = pvih->bmiHeader.biWidth;
  142. iHeight = pvih->bmiHeader.biHeight;
  143. }
  144. */
  145. if (iWidth > _rgSize.cx || iHeight > _rgSize.cy)
  146. {
  147. if ( Int32x32To64(_rgSize.cx, iHeight) > Int32x32To64(iWidth,_rgSize.cy) )
  148. {
  149. // constrained by height
  150. iWidth = MulDiv(iWidth, _rgSize.cy, iHeight);
  151. if (iWidth < 1) iWidth = 1;
  152. iHeight = _rgSize.cy;
  153. }
  154. else
  155. {
  156. // constrained by width
  157. iHeight = MulDiv(iHeight, _rgSize.cx, iWidth);
  158. if (iHeight < 1) iHeight = 1;
  159. iWidth = _rgSize.cx;
  160. }
  161. }
  162. CoTaskMemFree(mt.pbFormat);
  163. if (mt.pUnk)
  164. {
  165. mt.pUnk->Release();
  166. }
  167. }
  168. LONG lByteCount = 0;
  169. hr = _pmedia->GetBitmapBits(0.0, &lByteCount, NULL, iWidth, iHeight);
  170. if (SUCCEEDED(hr))
  171. {
  172. *ppbi = (BITMAPINFO *)LocalAlloc(LPTR, lByteCount);
  173. if (*ppbi)
  174. {
  175. hr = _pmedia->GetBitmapBits(0.0, 0, (char *)*ppbi, iWidth, iHeight);
  176. }
  177. else
  178. hr = E_OUTOFMEMORY;
  179. }
  180. }
  181. return hr;
  182. }
  183. void *CalcBitsOffsetInDIB(LPBITMAPINFO pBMI)
  184. {
  185. int ncolors = pBMI->bmiHeader.biClrUsed;
  186. if (ncolors == 0 && pBMI->bmiHeader.biBitCount <= 8)
  187. ncolors = 1 << pBMI->bmiHeader.biBitCount;
  188. if (pBMI->bmiHeader.biBitCount == 16 ||
  189. pBMI->bmiHeader.biBitCount == 32)
  190. {
  191. if (pBMI->bmiHeader.biCompression == BI_BITFIELDS)
  192. {
  193. ncolors = 3;
  194. }
  195. }
  196. return (void *) ((UCHAR *)&pBMI->bmiColors[0] + ncolors * sizeof(RGBQUAD));
  197. }
  198. STDMETHODIMP CVideoThumbnail::Extract(HBITMAP *phbmp)
  199. {
  200. *phbmp = NULL;
  201. BITMAPINFO *pbi;
  202. HRESULT hr = _GetThumbnailBits(&pbi);
  203. if (SUCCEEDED(hr))
  204. {
  205. HDC hdc = GetDC(NULL);
  206. if (hdc)
  207. {
  208. *phbmp = CreateDIBitmap(hdc, &pbi->bmiHeader, CBM_INIT, CalcBitsOffsetInDIB(pbi), pbi, DIB_RGB_COLORS);
  209. ReleaseDC(NULL, hdc);
  210. }
  211. else
  212. hr = E_FAIL;
  213. LocalFree(pbi);
  214. }
  215. return hr;
  216. }
  217. STDMETHODIMP CVideoThumbnail::GetLocation(LPWSTR pszPath, DWORD cch, DWORD *pdwPrioirty, const SIZE *prgSize, DWORD dwRecClrDepth, DWORD *pdwFlags)
  218. {
  219. HRESULT hr = (*pdwFlags & IEIFLAG_ASYNC) ? E_PENDING : S_OK;
  220. _rgSize = *prgSize;
  221. _dwRecClrDepth = dwRecClrDepth;
  222. *pdwFlags = IEIFLAG_CACHE;
  223. StrCpyNW(pszPath, _szPath, cch);
  224. return hr;
  225. }
  226. STDMETHODIMP CVideoThumbnail::GetClassID(CLSID *pClassID)
  227. {
  228. *pClassID = CLSID_VideoThumbnail;
  229. return S_OK;
  230. }
  231. STDMETHODIMP CVideoThumbnail::IsDirty(void)
  232. {
  233. return S_OK; // no
  234. }
  235. STDMETHODIMP CVideoThumbnail::Load(LPCOLESTR pszFileName, DWORD dwMode)
  236. {
  237. lstrcpynW(_szPath, pszFileName, ARRAYSIZE(_szPath));
  238. return S_OK;
  239. }
  240. STDMETHODIMP CVideoThumbnail::Save(LPCOLESTR pszFileName, BOOL fRemember)
  241. {
  242. return S_OK;
  243. }
  244. STDMETHODIMP CVideoThumbnail::SaveCompleted(LPCOLESTR pszFileName)
  245. {
  246. return S_OK;
  247. }
  248. STDMETHODIMP CVideoThumbnail::GetCurFile(LPOLESTR *ppszFileName)
  249. {
  250. return E_NOTIMPL;
  251. }
  252. // IServiceProvider
  253. STDMETHODIMP CVideoThumbnail::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  254. {
  255. // Return code for no service should be SVC_E_UNKNOWNSERVICE according to docs,
  256. // but that does not exist. Return E_INVALIDARG instead.
  257. HRESULT hr = E_INVALIDARG;
  258. *ppv = NULL;
  259. if (guidService == _uuidof(IWMReader))
  260. {
  261. IUnknown *punkCert;
  262. hr = WMCreateCertificate(&punkCert);
  263. if (SUCCEEDED(hr))
  264. {
  265. hr = punkCert->QueryInterface(riid, ppv);
  266. punkCert->Release();
  267. }
  268. }
  269. return hr;
  270. }
  271. STDAPI CVideoThumbnail_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  272. {
  273. HRESULT hr;
  274. CVideoThumbnail *pvt = new CVideoThumbnail();
  275. if (pvt)
  276. {
  277. *ppunk = SAFECAST(pvt, IExtractImage *);
  278. hr = S_OK;
  279. }
  280. else
  281. {
  282. *ppunk = NULL;
  283. hr = E_OUTOFMEMORY;
  284. }
  285. return hr;
  286. }