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.

465 lines
16 KiB

  1. // Copyright (c) 1997 - 1998 Microsoft Corporation. All Rights Reserved.
  2. // Util.cpp : Utility functions
  3. //
  4. #include "stdafx.h"
  5. #include "project.h"
  6. #include <fourcc.h>
  7. bool IsSameObject(IUnknown *pUnk1, IUnknown *pUnk2)
  8. {
  9. if (pUnk1 == pUnk2) {
  10. return TRUE;
  11. }
  12. //
  13. // NOTE: We can't use CComQIPtr here becuase it won't do the QueryInterface!
  14. //
  15. IUnknown *pRealUnk1;
  16. IUnknown *pRealUnk2;
  17. pUnk1->QueryInterface(IID_IUnknown, (void **)&pRealUnk1);
  18. pUnk2->QueryInterface(IID_IUnknown, (void **)&pRealUnk2);
  19. pRealUnk1->Release();
  20. pRealUnk2->Release();
  21. return (pRealUnk1 == pRealUnk2);
  22. }
  23. STDAPI_(void) TStringFromGUID(const GUID* pguid, LPTSTR pszBuf)
  24. {
  25. wsprintf(pszBuf, TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"), pguid->Data1,
  26. pguid->Data2, pguid->Data3, pguid->Data4[0], pguid->Data4[1], pguid->Data4[2],
  27. pguid->Data4[3], pguid->Data4[4], pguid->Data4[5], pguid->Data4[6], pguid->Data4[7]);
  28. }
  29. #ifndef UNICODE
  30. STDAPI_(void) WStringFromGUID(const GUID* pguid, LPWSTR pszBuf)
  31. {
  32. char szAnsi[40];
  33. TStringFromGUID(pguid, szAnsi);
  34. MultiByteToWideChar(CP_ACP, 0, szAnsi, -1, pszBuf, sizeof(szAnsi));
  35. }
  36. #endif
  37. //
  38. // Media Type helpers
  39. //
  40. void InitMediaType(AM_MEDIA_TYPE * pmt)
  41. {
  42. ZeroMemory(pmt, sizeof(*pmt));
  43. pmt->lSampleSize = 1;
  44. pmt->bFixedSizeSamples = TRUE;
  45. }
  46. bool IsEqualMediaType(AM_MEDIA_TYPE const & mt1, AM_MEDIA_TYPE const & mt2)
  47. {
  48. return ((IsEqualGUID(mt1.majortype,mt2.majortype) == TRUE) &&
  49. (IsEqualGUID(mt1.subtype,mt2.subtype) == TRUE) &&
  50. (IsEqualGUID(mt1.formattype,mt2.formattype) == TRUE) &&
  51. (mt1.cbFormat == mt2.cbFormat) &&
  52. ( (mt1.cbFormat == 0) ||
  53. ( memcmp(mt1.pbFormat, mt2.pbFormat, mt1.cbFormat) == 0)));
  54. }
  55. void CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource)
  56. {
  57. *pmtTarget = *pmtSource;
  58. if (pmtSource->cbFormat != 0) {
  59. _ASSERTE(pmtSource->pbFormat != NULL);
  60. pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat);
  61. if (pmtTarget->pbFormat == NULL) {
  62. pmtTarget->cbFormat = 0;
  63. } else {
  64. CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
  65. pmtTarget->cbFormat);
  66. }
  67. }
  68. if (pmtTarget->pUnk != NULL) {
  69. pmtTarget->pUnk->AddRef();
  70. }
  71. }
  72. AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE *pSrc)
  73. {
  74. AM_MEDIA_TYPE *pMediaType = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
  75. if (pMediaType ) {
  76. if (pSrc) {
  77. CopyMediaType(pMediaType,pSrc);
  78. } else {
  79. InitMediaType(pMediaType);
  80. }
  81. }
  82. return pMediaType;
  83. }
  84. void DeleteMediaType(AM_MEDIA_TYPE *pmt)
  85. {
  86. if (pmt) {
  87. FreeMediaType(*pmt);
  88. CoTaskMemFree((PVOID)pmt);
  89. }
  90. }
  91. void FreeMediaType(AM_MEDIA_TYPE& mt)
  92. {
  93. if (mt.cbFormat != 0) {
  94. CoTaskMemFree((PVOID)mt.pbFormat);
  95. // Strictly unnecessary but tidier
  96. mt.cbFormat = 0;
  97. mt.pbFormat = NULL;
  98. }
  99. if (mt.pUnk != NULL) {
  100. mt.pUnk->Release();
  101. mt.pUnk = NULL;
  102. }
  103. }
  104. // this also comes in useful when using the IEnumMediaTypes interface so
  105. // that you can copy a media type, you can do nearly the same by creating
  106. // a CMediaType object but as soon as it goes out of scope the destructor
  107. // will delete the memory it allocated (this takes a copy of the memory)
  108. AM_MEDIA_TYPE * WINAPI AllocVideoMediaType(const AM_MEDIA_TYPE * pmtSource)
  109. {
  110. AM_MEDIA_TYPE *pMediaType = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
  111. if (pMediaType) {
  112. VIDEOINFO *pVideoInfo = (VIDEOINFO *)CoTaskMemAlloc(sizeof(VIDEOINFO));
  113. if (pVideoInfo) {
  114. if (pmtSource) {
  115. *pMediaType = *pmtSource;
  116. CopyMemory(pVideoInfo, pmtSource->pbFormat, sizeof(*pVideoInfo));
  117. } else {
  118. ZeroMemory(pMediaType, sizeof(*pMediaType));
  119. ZeroMemory(pVideoInfo, sizeof(*pVideoInfo));
  120. pMediaType->majortype = MEDIATYPE_Video;
  121. pMediaType->cbFormat = sizeof(*pVideoInfo);
  122. pMediaType->formattype = FORMAT_VideoInfo;
  123. }
  124. pMediaType->pbFormat = (BYTE *)pVideoInfo;
  125. } else {
  126. CoTaskMemFree((PVOID)pMediaType);
  127. pMediaType = NULL;
  128. }
  129. }
  130. return pMediaType;
  131. }
  132. //
  133. // WARNING: The order of the entries in these tables is important! Make sure the
  134. // pixelformats and mediatypes line up!
  135. //
  136. const GUID * g_aFormats[] =
  137. {
  138. &MEDIASUBTYPE_RGB8,
  139. &MEDIASUBTYPE_RGB565,
  140. &MEDIASUBTYPE_RGB555,
  141. &MEDIASUBTYPE_RGB24,
  142. &MEDIASUBTYPE_RGB24,
  143. &MEDIASUBTYPE_RGB32,
  144. &MEDIASUBTYPE_RGB32
  145. };
  146. const DDPIXELFORMAT g_aPixelFormats[] =
  147. {
  148. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0, 8, 0, 0, 0, 0},
  149. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x0000F800, 0x000007E0, 0x0000001F, 0},
  150. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x00007C00, 0x000003E0, 0x0000001F, 0},
  151. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0},
  152. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0},
  153. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0},
  154. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0}
  155. };
  156. bool VideoSubtypeFromPixelFormat(const DDPIXELFORMAT *pPixelFormat, GUID *pSubType)
  157. {
  158. for( int i = 0; i < sizeof(g_aPixelFormats)/sizeof(g_aPixelFormats[0]); i++ )
  159. {
  160. if (ComparePixelFormats(&g_aPixelFormats[i], pPixelFormat)) {
  161. *pSubType = *g_aFormats[i];
  162. return true;
  163. }
  164. }
  165. // OK - try just using the fourcc
  166. if (pPixelFormat->dwFlags & DDPF_FOURCC) {
  167. *pSubType = FOURCCMap(pPixelFormat->dwFourCC);
  168. return true;
  169. }
  170. return false;
  171. }
  172. bool IsSupportedType(const DDPIXELFORMAT *pPixelFormat)
  173. {
  174. for( int i = 0; i < sizeof(g_aPixelFormats)/sizeof(g_aPixelFormats[0]); i++ )
  175. {
  176. if(ComparePixelFormats(&g_aPixelFormats[i], pPixelFormat)) {
  177. return true;
  178. }
  179. }
  180. return false;
  181. }
  182. const DDPIXELFORMAT * GetDefaultPixelFormatPtr(IDirectDraw *pDirectDraw)
  183. {
  184. if (pDirectDraw) {
  185. DDSURFACEDESC ddsd;
  186. ddsd.dwSize = sizeof(ddsd);
  187. if (SUCCEEDED(pDirectDraw->GetDisplayMode(&ddsd))) {
  188. for( int i = 0; i < sizeof(g_aPixelFormats)/sizeof(g_aPixelFormats[0]); i++ ) {
  189. if(memcmp(&g_aPixelFormats[i], &ddsd.ddpfPixelFormat, sizeof(g_aPixelFormats[i])) == 0) {
  190. return &g_aPixelFormats[i];
  191. }
  192. }
  193. }
  194. }
  195. return &g_aPixelFormats[0];
  196. }
  197. //
  198. // Helper function converts a DirectDraw surface to a media type.
  199. // The surface description must have:
  200. // Height
  201. // Width
  202. // lPitch -- Only used if DDSD_PITCH is set
  203. // PixelFormat
  204. // Initialise our output type based on the DirectDraw surface. As DirectDraw
  205. // only deals with top down display devices so we must convert the height of
  206. // the surface returned in the DDSURFACEDESC into a negative height. This is
  207. // because DIBs use a positive height to indicate a bottom up image. We also
  208. // initialise the other VIDEOINFO fields although they're hardly ever needed
  209. //
  210. // pmtTemplate is used to resolve any ambiguous mappings when we don't
  211. // want to change the connection type
  212. HRESULT ConvertSurfaceDescToMediaType(const DDSURFACEDESC *pSurfaceDesc,
  213. IDirectDrawPalette *pPalette,
  214. const RECT *pRect, BOOL bInvertSize, AM_MEDIA_TYPE **ppMediaType,
  215. AM_MEDIA_TYPE *pmtTemplate)
  216. {
  217. *ppMediaType = NULL;
  218. AM_MEDIA_TYPE *pMediaType = AllocVideoMediaType(NULL);
  219. if (pMediaType == NULL) {
  220. return E_OUTOFMEMORY;
  221. }
  222. if (!VideoSubtypeFromPixelFormat(&pSurfaceDesc->ddpfPixelFormat, &pMediaType->subtype)) {
  223. DeleteMediaType(pMediaType);
  224. return VFW_E_TYPE_NOT_ACCEPTED;
  225. }
  226. VIDEOINFO *pVideoInfo = (VIDEOINFO *)pMediaType->pbFormat;
  227. BITMAPINFOHEADER *pbmiHeader = &pVideoInfo->bmiHeader;
  228. // Convert a DDSURFACEDESC into a BITMAPINFOHEADER (see notes later). The
  229. // bit depth of the surface can be retrieved from the DDPIXELFORMAT field
  230. // in the DDpSurfaceDesc-> The documentation is a little misleading because
  231. // it says the field is permutations of DDBD_*'s however in this case the
  232. // field is initialised by DirectDraw to be the actual surface bit depth
  233. pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);
  234. if (pSurfaceDesc->dwFlags & DDSD_PITCH) {
  235. pbmiHeader->biWidth = pSurfaceDesc->lPitch;
  236. // Convert the pitch from a byte count to a pixel count.
  237. // For some weird reason if the format is not a standard bit depth the
  238. // width field in the BITMAPINFOHEADER should be set to the number of
  239. // bytes instead of the width in pixels. This supports odd YUV formats
  240. // like IF09 which uses 9bpp.
  241. int bpp = pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount;
  242. if (bpp == 8 || bpp == 16 || bpp == 24 || bpp == 32) {
  243. pbmiHeader->biWidth /= (bpp / 8); // Divide by number of BYTES per pixel.
  244. }
  245. } else {
  246. pbmiHeader->biWidth = pSurfaceDesc->dwWidth;
  247. // BUGUBUG -- Do something odd here with strange YUV pixel formats? Or does it matter?
  248. }
  249. pbmiHeader->biHeight = pSurfaceDesc->dwHeight;
  250. if (bInvertSize) {
  251. pbmiHeader->biHeight = -pbmiHeader->biHeight;
  252. }
  253. pbmiHeader->biPlanes = 1;
  254. pbmiHeader->biBitCount = (USHORT) pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount;
  255. pbmiHeader->biCompression = pSurfaceDesc->ddpfPixelFormat.dwFourCC;
  256. //pbmiHeader->biXPelsPerMeter = 0;
  257. //pbmiHeader->biYPelsPerMeter = 0;
  258. //pbmiHeader->biClrUsed = 0;
  259. //pbmiHeader->biClrImportant = 0;
  260. // For true colour RGB formats tell the source there are bit fields
  261. // unless it's regular RGB555
  262. //
  263. // Try to preserve BI_RGB for RGB32 from template in case
  264. // connection wasn't queried for a BI_BITFIELDS -> BI_RGB switch
  265. _ASSERTE(!pmtTemplate || pmtTemplate->formattype == FORMAT_VideoInfo);
  266. DWORD dwSrcComp = pmtTemplate ?
  267. ((VIDEOINFO *)pmtTemplate->pbFormat)->bmiHeader.biCompression :
  268. (DWORD)-1;
  269. if (pbmiHeader->biCompression == BI_RGB) {
  270. if (pbmiHeader->biBitCount == 16 &&
  271. pMediaType->subtype != MEDIASUBTYPE_RGB555 ||
  272. pbmiHeader->biBitCount == 32 && dwSrcComp == BI_BITFIELDS) {
  273. pbmiHeader->biCompression = BI_BITFIELDS;
  274. }
  275. }
  276. if (PALETTISED(pVideoInfo)) {
  277. pbmiHeader->biClrUsed = 1 << pbmiHeader->biBitCount;
  278. if (pPalette) {
  279. pPalette->GetEntries(0, 0, pbmiHeader->biClrUsed, (LPPALETTEENTRY)&pVideoInfo->bmiColors);
  280. for (unsigned int i = 0; i < pbmiHeader->biClrUsed; i++) {
  281. BYTE tempRed = pVideoInfo->bmiColors[i].rgbRed;
  282. pVideoInfo->bmiColors[i].rgbRed = pVideoInfo->bmiColors[i].rgbBlue;
  283. pVideoInfo->bmiColors[i].rgbBlue = tempRed;
  284. }
  285. }
  286. }
  287. // The RGB bit fields are in the same place as for YUV formats
  288. if (pbmiHeader->biCompression != BI_RGB) {
  289. pVideoInfo->dwBitMasks[0] = pSurfaceDesc->ddpfPixelFormat.dwRBitMask;
  290. pVideoInfo->dwBitMasks[1] = pSurfaceDesc->ddpfPixelFormat.dwGBitMask;
  291. pVideoInfo->dwBitMasks[2] = pSurfaceDesc->ddpfPixelFormat.dwBBitMask;
  292. }
  293. pbmiHeader->biSizeImage = DIBSIZE(*pbmiHeader);
  294. // Complete the rest of the VIDEOINFO fields
  295. //pVideoInfo->dwBitRate = 0;
  296. //pVideoInfo->dwBitErrorRate = 0;
  297. //pVideoInfo->AvgTimePerFrame = 0;
  298. // And finish it off with the other media type fields
  299. // pMediaType->formattype = FORMAT_VideoInfo;
  300. pMediaType->lSampleSize = pbmiHeader->biSizeImage;
  301. pMediaType->bFixedSizeSamples = TRUE;
  302. //pMediaType->bTemporalCompression = FALSE;
  303. // Initialise the source and destination rectangles
  304. if (pRect) {
  305. pVideoInfo->rcSource.right = pRect->right - pRect->left;
  306. pVideoInfo->rcSource.bottom = pRect->bottom - pRect->top;
  307. pVideoInfo->rcTarget = *pRect;
  308. } else {
  309. //pVideoInfo->rcTarget.left = pVideoInfo->rcTarget.top = 0;
  310. pVideoInfo->rcTarget.right = pSurfaceDesc->dwWidth;
  311. pVideoInfo->rcTarget.bottom = pSurfaceDesc->dwHeight;
  312. //pVideoInfo->rcSource.left = pVideoInfo->rcSource.top = 0;
  313. pVideoInfo->rcSource.right = pSurfaceDesc->dwWidth;
  314. pVideoInfo->rcSource.bottom = pSurfaceDesc->dwHeight;
  315. }
  316. *ppMediaType = pMediaType;
  317. return S_OK;
  318. }
  319. bool PixelFormatFromVideoSubtype(REFGUID refSubType, DDPIXELFORMAT *pPixelFormat)
  320. {
  321. for( int i = 0; i < sizeof(g_aFormats)/sizeof(g_aFormats[0]); i++ )
  322. {
  323. if (*g_aFormats[i] == refSubType)
  324. {
  325. *pPixelFormat = g_aPixelFormats[i];
  326. return TRUE;
  327. }
  328. }
  329. return FALSE;
  330. }
  331. HRESULT ConvertMediaTypeToSurfaceDesc(const AM_MEDIA_TYPE *pmt,
  332. IDirectDraw *pDD,
  333. IDirectDrawPalette **ppPalette,
  334. LPDDSURFACEDESC pSurfaceDesc)
  335. {
  336. *ppPalette = NULL;
  337. if (pmt->majortype != MEDIATYPE_Video ||
  338. pmt->formattype != FORMAT_VideoInfo) {
  339. return VFW_E_TYPE_NOT_ACCEPTED;
  340. }
  341. VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat;
  342. BITMAPINFOHEADER *pbmiHeader = &pVideoInfo->bmiHeader;
  343. pSurfaceDesc->dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  344. // Should really look at rcTarget here if it's not empty but there are
  345. // very few valid cases where it makes sense so rather than risk
  346. // regressions we're not going to change it.
  347. pSurfaceDesc->dwHeight = (pbmiHeader->biHeight > 0) ? pbmiHeader->biHeight : -pbmiHeader->biHeight;
  348. pSurfaceDesc->dwWidth = pbmiHeader->biWidth;
  349. if (PixelFormatFromVideoSubtype(pmt->subtype, &pSurfaceDesc->ddpfPixelFormat)) {
  350. if (pDD && pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == 8) {
  351. //
  352. // The RGBQUAD and PALETTEENTRY sturctures have Red and Blue swapped so
  353. // we can't do a simple memory copy.
  354. //
  355. PALETTEENTRY aPaletteEntry[256];
  356. int iEntries = min(256, pVideoInfo->bmiHeader.biClrUsed);
  357. if (0 == iEntries && pmt->cbFormat >=
  358. (DWORD)FIELD_OFFSET(VIDEOINFO, bmiColors[256])) {
  359. iEntries = 256;
  360. }
  361. ZeroMemory(aPaletteEntry, sizeof(aPaletteEntry));
  362. for (int i = 0; i < iEntries; i++) {
  363. aPaletteEntry[i].peRed = pVideoInfo->bmiColors[i].rgbRed;
  364. aPaletteEntry[i].peGreen = pVideoInfo->bmiColors[i].rgbGreen;
  365. aPaletteEntry[i].peBlue = pVideoInfo->bmiColors[i].rgbBlue;
  366. }
  367. return pDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, aPaletteEntry, ppPalette, NULL);
  368. }
  369. return S_OK;
  370. } else {
  371. return VFW_E_TYPE_NOT_ACCEPTED;
  372. }
  373. }
  374. // Helper to compare pixel formats
  375. bool ComparePixelFormats(const DDPIXELFORMAT *pFormat1,
  376. const DDPIXELFORMAT *pFormat2)
  377. {
  378. // Compare the flags
  379. if (pFormat1->dwSize != pFormat2->dwSize) {
  380. return false;
  381. }
  382. if ((pFormat1->dwFlags ^ pFormat2->dwFlags) & (DDPF_RGB |
  383. DDPF_PALETTEINDEXED8 |
  384. DDPF_PALETTEINDEXED4 |
  385. DDPF_PALETTEINDEXED2 |
  386. DDPF_PALETTEINDEXED1 |
  387. DDPF_PALETTEINDEXEDTO8 |
  388. DDPF_YUV)
  389. ) {
  390. return false;
  391. }
  392. return (0 == memcmp(&pFormat1->dwFourCC, &pFormat2->dwFourCC,
  393. FIELD_OFFSET(DDPIXELFORMAT, dwRGBAlphaBitMask) -
  394. FIELD_OFFSET(DDPIXELFORMAT, dwFourCC))
  395. );
  396. }