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.

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