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.

1794 lines
58 KiB

  1. #include <objbase.h>
  2. #include <qos.h>
  3. #include <winsock2.h>
  4. #define INITGUID // Only do this in one file
  5. #include "capture.h"
  6. #include "frameop.h"
  7. #include "filters.h"
  8. #include <confdbg.h>
  9. #include <avutil.h>
  10. #include "..\nac\utils.h"
  11. #include "vidinout.h"
  12. #include "vcmstrm.h"
  13. CCaptureChain::CCaptureChain(void)
  14. {
  15. m_opchain = NULL;
  16. m_filterchain = NULL;
  17. m_filtertags = NULL;
  18. InitializeCriticalSection(&m_capcs);
  19. }
  20. CCaptureChain::~CCaptureChain(void)
  21. {
  22. CFrameOp *pchain;
  23. EnterCriticalSection(&m_capcs);
  24. pchain = m_opchain;
  25. m_opchain = NULL;
  26. LeaveCriticalSection(&m_capcs);
  27. if (pchain)
  28. pchain->Release();
  29. DeleteCriticalSection(&m_capcs);
  30. }
  31. STDMETHODIMP
  32. CCaptureChain::GrabFrame(
  33. IBitmapSurface** ppBS
  34. )
  35. {
  36. CFrameOp *cfo;
  37. HRESULT hres;
  38. *ppBS = NULL;
  39. EnterCriticalSection(&m_capcs);
  40. if (m_opchain) {
  41. m_opchain->AddRef(); // lock chain - prevents chain from being released
  42. cfo = m_opchain;
  43. while (cfo && ((hres = cfo->DoOp(ppBS)) == NOERROR)) {
  44. cfo = cfo->m_next;
  45. }
  46. if (*ppBS && hres != NOERROR) {
  47. // failed conversion, so discard last pBSin frame
  48. (*ppBS)->Release();
  49. *ppBS = NULL;
  50. }
  51. m_opchain->Release(); // unlock chain
  52. }
  53. else
  54. hres = E_UNEXPECTED;
  55. LeaveCriticalSection(&m_capcs);
  56. return hres;
  57. }
  58. typedef struct _CONVERTINFO
  59. {
  60. long ci_width;
  61. long ci_height;
  62. long ci_dstwidth;
  63. long ci_dstheight;
  64. long ci_delta;
  65. long ci_UVDownSampling;
  66. long ci_ZeroingDWORD;
  67. void (*ci_Copy) (LPBYTE *, LPBYTE *);
  68. RGBQUAD ci_colortable[1];
  69. } CONVERTINFO, FAR* PCONVERTINFO;
  70. #ifdef ENABLE_ZOOM_CODE
  71. typedef struct _rv
  72. {
  73. long x_i;
  74. long p;
  75. long p1;
  76. } ROW_VALUES;
  77. typedef struct _ZOOMCONVERTINFO
  78. {
  79. long ci_width;
  80. long ci_height;
  81. long ci_dstwidth;
  82. long ci_dstheight;
  83. ROW_VALUES *ci_rptr;
  84. RGBQUAD ci_colortable[1];
  85. } ZOOMCONVERTINFO, FAR* PZOOMCONVERTINFO;
  86. #endif // ENABLE_ZOOM_CODE
  87. // sub worker routines for conversion of RGB16, RGB24 and RGB32 to RGB24
  88. BYTE Byte16[32] = {0,8,16,25,33,41,49,58,66,74,82,91,99,107,115,123,132,140,148,156,165,173,
  89. 181,189,197,206,214,222,230,239,247,255};
  90. void Copy16(LPBYTE *ppsrc, LPBYTE *ppdst)
  91. {
  92. DWORD tmp;
  93. tmp = *(WORD *)(*ppsrc);
  94. *(*ppdst)++ = Byte16[tmp & 31]; // blue
  95. *(*ppdst)++ = Byte16[(tmp >> 5) & 31]; // green
  96. *(*ppdst)++ = Byte16[(tmp >> 10) & 31]; // red
  97. *ppsrc += 2;
  98. }
  99. void Copy24(LPBYTE *ppsrc, LPBYTE *ppdst)
  100. {
  101. *(*ppdst)++ = *(*ppsrc)++; // blue
  102. *(*ppdst)++ = *(*ppsrc)++; // green
  103. *(*ppdst)++ = *(*ppsrc)++; // red
  104. }
  105. void Copy32(LPBYTE *ppsrc, LPBYTE *ppdst)
  106. {
  107. *(*ppdst)++ = *(*ppsrc)++; // blue
  108. *(*ppdst)++ = *(*ppsrc)++; // green
  109. *(*ppdst)++ = *(*ppsrc)++; // red
  110. (*ppsrc)++;
  111. }
  112. // worker routine to shrink an RGB16, RGB24 or RGB32 in half (width & height)
  113. // result is RGB24
  114. BOOL DoHalfSize(
  115. IBitmapSurface* pbsIn,
  116. IBitmapSurface* pbsOut,
  117. PCONVERTINFO refdata
  118. )
  119. {
  120. LPBYTE pBits, pCvtBits, pIn, pOut;
  121. long ipitch, opitch;
  122. long x, y;
  123. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  124. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  125. ipitch = (ipitch * 2) - (refdata->ci_dstwidth * 2 * refdata->ci_delta);
  126. opitch -= refdata->ci_dstwidth * 3; // bytes at end of each row
  127. pIn = pBits;
  128. pOut = pCvtBits;
  129. for (y = 0; y < refdata->ci_dstheight; y++) {
  130. for (x = 0; x < refdata->ci_dstwidth; x++) {
  131. refdata->ci_Copy(&pIn, &pOut);
  132. pIn += refdata->ci_delta; // skip to next pixel
  133. }
  134. pIn += ipitch; // get to start of row after next
  135. pOut += opitch; // get to start of next row
  136. }
  137. pbsIn->UnlockBits(NULL, pBits);
  138. pbsOut->UnlockBits(NULL, pCvtBits);
  139. return TRUE;
  140. }
  141. // worker routine to shrink an RGB4 in half (width & height)
  142. // result is RGB24
  143. BOOL DoHalfSize4(
  144. IBitmapSurface* pbsIn,
  145. IBitmapSurface* pbsOut,
  146. PCONVERTINFO refdata
  147. )
  148. {
  149. LPBYTE pBits, pCvtBits, pIn, pOut;
  150. long ipitch, opitch;
  151. long x, y;
  152. BYTE pixel;
  153. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  154. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  155. ipitch = (ipitch * 2) - refdata->ci_dstwidth;
  156. opitch -= refdata->ci_dstwidth * 3; // bytes at end of each row
  157. pIn = pBits;
  158. pOut = pCvtBits;
  159. for (y = 0; y < refdata->ci_dstheight; y++) {
  160. for (x = 0; x < refdata->ci_dstwidth; x++) {
  161. pixel = (*pIn++/16) & 15;
  162. *pOut++ = refdata->ci_colortable[pixel].rgbBlue;
  163. *pOut++ = refdata->ci_colortable[pixel].rgbGreen;
  164. *pOut++ = refdata->ci_colortable[pixel].rgbRed;
  165. }
  166. pIn += ipitch; // get to start of row after next
  167. pOut += opitch; // get to start of next row
  168. }
  169. pbsIn->UnlockBits(NULL, pBits);
  170. pbsOut->UnlockBits(NULL, pCvtBits);
  171. return TRUE;
  172. }
  173. // worker routine to shrink an RGB8 in half (width & height)
  174. // result is RGB24
  175. BOOL DoHalfSize8(
  176. IBitmapSurface* pbsIn,
  177. IBitmapSurface* pbsOut,
  178. PCONVERTINFO refdata
  179. )
  180. {
  181. LPBYTE pBits, pCvtBits, pIn, pOut;
  182. long ipitch, opitch;
  183. long x, y;
  184. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  185. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  186. ipitch = (ipitch * 2) - refdata->ci_dstwidth * 2;
  187. opitch -= refdata->ci_dstwidth * 3; // bytes at end of each row
  188. pIn = pBits;
  189. pOut = pCvtBits;
  190. for (y = 0; y < refdata->ci_dstheight; y++) {
  191. for (x = 0; x < refdata->ci_dstwidth; x++) {
  192. *pOut++ = refdata->ci_colortable[*pIn].rgbBlue;
  193. *pOut++ = refdata->ci_colortable[*pIn].rgbGreen;
  194. *pOut++ = refdata->ci_colortable[*pIn].rgbRed;
  195. pIn += 2;
  196. }
  197. pIn += ipitch; // get to start of row after next
  198. pOut += opitch; // get to start of next row
  199. }
  200. pbsIn->UnlockBits(NULL, pBits);
  201. pbsOut->UnlockBits(NULL, pCvtBits);
  202. return TRUE;
  203. }
  204. // worker routine to shrink a YVU9 or YUV12 in half (width & height)
  205. // result is YVU9 or YUV12
  206. BOOL DoHalfSizeYUVPlanar(
  207. IBitmapSurface* pbsIn,
  208. IBitmapSurface* pbsOut,
  209. PCONVERTINFO refdata
  210. )
  211. {
  212. LPBYTE pBits, pCvtBits, pIn, pIn2, pOut;
  213. long pitch;
  214. long x, y, w, h;
  215. pbsIn->LockBits(NULL, 0, (void**)&pBits, &pitch);
  216. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &pitch);
  217. // Do the Y component first
  218. pitch = refdata->ci_width * 2 - refdata->ci_dstwidth * 2; // amount to add for skip
  219. pIn = pBits;
  220. pOut = pCvtBits;
  221. for (y = 0; y < refdata->ci_dstheight; y++) {
  222. for (x = 0; x < refdata->ci_dstwidth; x++) {
  223. *pOut++ = *pIn++;
  224. pIn++; // skip to next pixel
  225. }
  226. pIn += pitch; // get to start of row after next
  227. }
  228. // if source height is odd, then we've added 1 line too many onto pIn
  229. if (refdata->ci_height & 1)
  230. pIn -= refdata->ci_width;
  231. // Do the first color component next
  232. h = refdata->ci_dstheight / refdata->ci_UVDownSampling;
  233. w = refdata->ci_dstwidth / refdata->ci_UVDownSampling;
  234. pitch = refdata->ci_width / refdata->ci_UVDownSampling * 2 - w * 2;
  235. pIn2 = pIn + refdata->ci_width / refdata->ci_UVDownSampling;
  236. for (y = 0; y < h; y++) {
  237. for (x = 0; x < w; x++) {
  238. *pOut++ = (*pIn++ + *(++pIn) + *pIn2++ + *(++pIn2)) / 4;
  239. }
  240. pIn += pitch; // get to start of row after next
  241. pIn2 += pitch; // get to start of row after next
  242. }
  243. // if source height is odd, then we've added 1 line too many onto pIn
  244. if (refdata->ci_height & 1)
  245. pIn -= refdata->ci_width / refdata->ci_UVDownSampling;
  246. // Do the second color component next
  247. pIn2 = pIn + refdata->ci_width / refdata->ci_UVDownSampling;
  248. for (y = 0; y < h; y++) {
  249. for (x = 0; x < w; x++) {
  250. *pOut++ = (*pIn++ + *(++pIn) + *pIn2++ + *(++pIn2)) / 4;
  251. }
  252. pIn += pitch; // get to start of row after next
  253. pIn2 += pitch; // get to start of row after next
  254. }
  255. pbsIn->UnlockBits(NULL, pBits);
  256. pbsOut->UnlockBits(NULL, pCvtBits);
  257. return TRUE;
  258. }
  259. // worker routine to shrink a YUV packed DIB in half (width & height)
  260. // result is YUY2, or UYVY
  261. BOOL DoHalfSizeYUVPacked(
  262. IBitmapSurface* pbsIn,
  263. IBitmapSurface* pbsOut,
  264. PCONVERTINFO refdata
  265. )
  266. {
  267. LPBYTE pBits, pCvtBits;
  268. LPDWORD pIn, pOut;
  269. long ipitch, opitch;
  270. long x, y;
  271. long prelines, postlines, prebytes, postbytes, ibytes, obytes;
  272. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  273. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  274. pIn = (LPDWORD)pBits;
  275. pOut = (LPDWORD)pCvtBits;
  276. // copy one line out of two
  277. for (y = 0; y < refdata->ci_dstheight; y++) {
  278. // copy one pixel out of two
  279. for (x = 0; x < refdata->ci_dstwidth / 2; x++) {
  280. *pOut++ = *pIn++;
  281. pIn++; // skip to next pixel
  282. }
  283. pIn += refdata->ci_width / 2; // skip to next line
  284. }
  285. pbsIn->UnlockBits(NULL, pBits);
  286. pbsOut->UnlockBits(NULL, pCvtBits);
  287. return TRUE;
  288. }
  289. // worker routine to shrink an RGB16, RGB24 or RGB32 by cropping
  290. // result is RGB24
  291. BOOL Crop(
  292. IBitmapSurface* pbsIn,
  293. IBitmapSurface* pbsOut,
  294. PCONVERTINFO refdata
  295. )
  296. {
  297. LPBYTE pBits, pCvtBits, pIn, pOut;
  298. long ipitch, opitch;
  299. long extra, x, y;
  300. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  301. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  302. pOut = pCvtBits;
  303. // pIn starts by skipping half of the height change
  304. pIn = pBits + (refdata->ci_height - refdata->ci_dstheight) / 2 * ipitch;
  305. // extra = # of source bytes per scan line that are to be cropped
  306. extra = (refdata->ci_width - refdata->ci_dstwidth) * refdata->ci_delta;
  307. // advance pIn by half of extra to crop left most pixels
  308. pIn += extra / 2;
  309. // adjust ipitch so we can add it at the end of each scan to get to start of next scan
  310. ipitch = ipitch - (refdata->ci_width * refdata->ci_delta) + extra;
  311. opitch -= refdata->ci_dstwidth * 3; // bytes at end of each row
  312. for (y = 0; y < refdata->ci_dstheight; y++) {
  313. for (x = 0; x < refdata->ci_dstwidth; x++) {
  314. refdata->ci_Copy(&pIn, &pOut);
  315. }
  316. pIn += ipitch; // get to start of next row
  317. pOut += opitch; // get to start of next row
  318. }
  319. pbsIn->UnlockBits(NULL, pBits);
  320. pbsOut->UnlockBits(NULL, pCvtBits);
  321. return TRUE;
  322. }
  323. // worker routine to shrink an RGB4 by cropping
  324. // result is RGB24
  325. BOOL Crop4(
  326. IBitmapSurface* pbsIn,
  327. IBitmapSurface* pbsOut,
  328. PCONVERTINFO refdata
  329. )
  330. {
  331. LPBYTE pBits, pCvtBits, pIn, pOut;
  332. long ipitch, opitch;
  333. long extra, x, y;
  334. BYTE val, pixel;
  335. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  336. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  337. pOut = pCvtBits;
  338. // pIn starts by skipping half of the height change
  339. pIn = pBits + (refdata->ci_height - refdata->ci_dstheight) / 2 * ipitch;
  340. // extra = # of source bytes per scan line that are to be cropped
  341. extra = (refdata->ci_width - refdata->ci_dstwidth) / 2;
  342. // advance pIn by half of extra to crop left most pixels
  343. pIn += extra / 2;
  344. // adjust ipitch so we can add it at the end of each scan to get to start of next scan
  345. ipitch = ipitch - (refdata->ci_width / 2) + extra;
  346. opitch -= refdata->ci_dstwidth * 3; // bytes at end of each row
  347. for (y = 0; y < refdata->ci_dstheight; y++) {
  348. for (x = 0; x < refdata->ci_dstwidth/2; x++) {
  349. val = *pIn++;
  350. pixel = (val/16) & 15;
  351. *pOut++ = refdata->ci_colortable[pixel].rgbBlue;
  352. *pOut++ = refdata->ci_colortable[pixel].rgbGreen;
  353. *pOut++ = refdata->ci_colortable[pixel].rgbRed;
  354. pixel = val & 15;
  355. *pOut++ = refdata->ci_colortable[pixel].rgbBlue;
  356. *pOut++ = refdata->ci_colortable[pixel].rgbGreen;
  357. *pOut++ = refdata->ci_colortable[pixel].rgbRed;
  358. }
  359. pIn += ipitch; // get to start of next row
  360. pOut += opitch; // get to start of next row
  361. }
  362. pbsIn->UnlockBits(NULL, pBits);
  363. pbsOut->UnlockBits(NULL, pCvtBits);
  364. return TRUE;
  365. }
  366. // worker routine to shrink an RGB8 by cropping
  367. // result is RGB24
  368. BOOL Crop8(
  369. IBitmapSurface* pbsIn,
  370. IBitmapSurface* pbsOut,
  371. PCONVERTINFO refdata
  372. )
  373. {
  374. LPBYTE pBits, pCvtBits, pIn, pOut;
  375. long ipitch, opitch;
  376. long extra, x, y;
  377. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  378. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  379. pOut = pCvtBits;
  380. // pIn starts by skipping half of the height change
  381. pIn = pBits + (refdata->ci_height - refdata->ci_dstheight) / 2 * ipitch;
  382. // extra = # of source bytes per scan line that are to be cropped
  383. extra = refdata->ci_width - refdata->ci_dstwidth;
  384. // advance pIn by half of extra to crop left most pixels
  385. pIn += extra / 2;
  386. // adjust ipitch so we can add it at the end of each scan to get to start of next scan
  387. ipitch = ipitch - refdata->ci_width + extra;
  388. opitch -= refdata->ci_dstwidth * 3; // bytes at end of each row
  389. for (y = 0; y < refdata->ci_dstheight; y++) {
  390. for (x = 0; x < refdata->ci_dstwidth; x++) {
  391. *pOut++ = refdata->ci_colortable[*pIn].rgbBlue;
  392. *pOut++ = refdata->ci_colortable[*pIn].rgbGreen;
  393. *pOut++ = refdata->ci_colortable[*pIn++].rgbRed;
  394. }
  395. pIn += ipitch; // get to start of next row
  396. pOut += opitch; // get to start of next row
  397. }
  398. pbsIn->UnlockBits(NULL, pBits);
  399. pbsOut->UnlockBits(NULL, pCvtBits);
  400. return TRUE;
  401. }
  402. // worker routine to shrink a YVU9 or YUV12 by cropping
  403. // result is YVU9 or YUV12
  404. BOOL CropYUVPlanar(
  405. IBitmapSurface* pbsIn,
  406. IBitmapSurface* pbsOut,
  407. PCONVERTINFO refdata
  408. )
  409. {
  410. LPBYTE pBits, pCvtBits, pIn, pOut;
  411. long pitch, prelines, bytes, prebytes;
  412. long extra, y;
  413. pbsIn->LockBits(NULL, 0, (void**)&pBits, &pitch);
  414. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &pitch);
  415. pOut = pCvtBits;
  416. // pIn starts by skipping half of the height change
  417. prelines = ((refdata->ci_height - refdata->ci_dstheight) >> 1) / refdata->ci_UVDownSampling * refdata->ci_UVDownSampling;
  418. pIn = pBits + prelines * refdata->ci_width;
  419. // extra = # of source bytes per scan line that are to be cropped
  420. extra = refdata->ci_width - refdata->ci_dstwidth;
  421. prebytes = (extra >> 1) / refdata->ci_UVDownSampling * refdata->ci_UVDownSampling;
  422. // advance pIn by half of extra to crop left most pixels
  423. pIn += prebytes;
  424. // Do the Y component first
  425. pitch = extra + refdata->ci_dstwidth;
  426. for (y = 0; y < refdata->ci_dstheight; y++) {
  427. CopyMemory (pOut, pIn, refdata->ci_dstwidth);
  428. pIn += pitch;
  429. pOut += refdata->ci_dstwidth;
  430. }
  431. // Do the first color component next
  432. prelines /= refdata->ci_UVDownSampling;
  433. prebytes /= refdata->ci_UVDownSampling;
  434. pIn = pBits + (refdata->ci_width * refdata->ci_height) + // skip Y section
  435. prelines * refdata->ci_width / refdata->ci_UVDownSampling + // skip half of the crop lines
  436. prebytes; // skip half of the crop pixels
  437. pitch /= refdata->ci_UVDownSampling;
  438. bytes = refdata->ci_dstwidth / refdata->ci_UVDownSampling;
  439. for (y=0; y < refdata->ci_dstheight / refdata->ci_UVDownSampling; y++)
  440. {
  441. CopyMemory (pOut, pIn, bytes);
  442. pIn += pitch;
  443. pOut += bytes;
  444. }
  445. // Do the second color component next
  446. pIn = pBits + (refdata->ci_width * refdata->ci_height) + // skip Y section
  447. (refdata->ci_width * refdata->ci_height) / (refdata->ci_UVDownSampling * refdata->ci_UVDownSampling) + // skip first color component section
  448. prelines * refdata->ci_width / refdata->ci_UVDownSampling + // skip half of the crop lines
  449. prebytes; // skip half of the crop pixels
  450. for (y=0; y < refdata->ci_dstheight / refdata->ci_UVDownSampling; y++)
  451. {
  452. CopyMemory (pOut, pIn, bytes);
  453. pIn += pitch;
  454. pOut += bytes;
  455. }
  456. pbsIn->UnlockBits(NULL, pBits);
  457. pbsOut->UnlockBits(NULL, pCvtBits);
  458. return TRUE;
  459. }
  460. // worker routine to shrink a YUV packed DIB by cropping
  461. // result is YUY2 or UYVY
  462. BOOL CropYUVPacked(
  463. IBitmapSurface* pbsIn,
  464. IBitmapSurface* pbsOut,
  465. PCONVERTINFO refdata
  466. )
  467. {
  468. LPBYTE pBits, pCvtBits, pIn, pOut;
  469. long ipitch, opitch;
  470. long extra, x, y;
  471. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  472. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  473. pOut = pCvtBits;
  474. // pIn starts by skipping half of the height change
  475. pIn = pBits + (refdata->ci_height - refdata->ci_dstheight) * refdata->ci_width * 2;
  476. // extra = # of source bytes per scan line that are to be cropped
  477. extra = (refdata->ci_width - refdata->ci_dstwidth) * 2;
  478. // advance pIn by half of extra to crop left most pixels
  479. pIn += extra / 2;
  480. // adjust ipitch so we can add it at the end of each scan to get to start of next scan
  481. ipitch = refdata->ci_width * 2;
  482. opitch = refdata->ci_dstwidth * 2; // bytes at end of each row
  483. for (y = 0; y < refdata->ci_dstheight; y++) {
  484. for (x = 0; x < refdata->ci_dstwidth; x++) {
  485. CopyMemory(pOut, pIn, refdata->ci_dstwidth * 2);
  486. }
  487. pIn += ipitch; // get to start of next row
  488. pOut += opitch; // get to start of next row
  489. }
  490. pbsIn->UnlockBits(NULL, pBits);
  491. pbsOut->UnlockBits(NULL, pCvtBits);
  492. return TRUE;
  493. }
  494. // routine to prepare for calling shrink worker routines
  495. // it allocates and initializes a reference data structure
  496. BOOL
  497. InitShrink(
  498. LPBITMAPINFOHEADER lpbmhIn,
  499. long desiredwidth,
  500. long desiredheight,
  501. LPBITMAPINFOHEADER *lpbmhOut,
  502. FRAMECONVERTPROC **convertproc,
  503. LPVOID *refdata
  504. )
  505. {
  506. PCONVERTINFO pcvt;
  507. DWORD dwSize;
  508. long crop_ratio, black_ratio, target_size;
  509. *convertproc = NULL;
  510. *refdata = NULL;
  511. if ((lpbmhIn->biCompression != VIDEO_FORMAT_BI_RGB) &&
  512. (lpbmhIn->biCompression != VIDEO_FORMAT_YVU9) &&
  513. (lpbmhIn->biCompression != VIDEO_FORMAT_YUY2) &&
  514. (lpbmhIn->biCompression != VIDEO_FORMAT_UYVY) &&
  515. (lpbmhIn->biCompression != VIDEO_FORMAT_I420) &&
  516. (lpbmhIn->biCompression != VIDEO_FORMAT_IYUV))
  517. return FALSE;
  518. // calculate size of convertinfo struct, if we need a colortable, then add 256 entries
  519. // else subtract off the 1 built into the struct definition
  520. dwSize = sizeof(CONVERTINFO) - sizeof(RGBQUAD);
  521. if (lpbmhIn->biBitCount <= 8)
  522. dwSize += 256 * sizeof(RGBQUAD);
  523. // for RGB, and YUV input formats, we know that the output format will never need
  524. // an attached color table, so we can allocate lpbmhOut without one
  525. if ((pcvt = (PCONVERTINFO)LocalAlloc(LPTR, dwSize)) &&
  526. (*lpbmhOut = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, lpbmhIn->biSize))) {
  527. CopyMemory(*lpbmhOut, lpbmhIn, lpbmhIn->biSize);
  528. pcvt->ci_width = lpbmhIn->biWidth;
  529. pcvt->ci_height = lpbmhIn->biHeight;
  530. target_size = desiredwidth * desiredheight;
  531. crop_ratio = pcvt->ci_width * pcvt->ci_height;
  532. black_ratio = ((target_size - (crop_ratio / 4)) * 100) / target_size;
  533. crop_ratio = ((crop_ratio - target_size) * 100) / crop_ratio;
  534. if (crop_ratio < black_ratio) {
  535. // cropping the source makes more sense
  536. pcvt->ci_dstwidth = desiredwidth;
  537. pcvt->ci_dstheight = desiredheight;
  538. crop_ratio = 1; // flag that we'll crop
  539. }
  540. else {
  541. // halfsizing makes more sense
  542. pcvt->ci_dstwidth = lpbmhIn->biWidth / 2;
  543. pcvt->ci_dstheight = lpbmhIn->biHeight / 2;
  544. crop_ratio = 0; // flag that we'll half size
  545. }
  546. (*lpbmhOut)->biWidth = pcvt->ci_dstwidth;
  547. (*lpbmhOut)->biHeight = pcvt->ci_dstheight;
  548. // copy colortable from input bitmapinfoheader
  549. if (lpbmhIn->biBitCount <= 8)
  550. CopyMemory(&pcvt->ci_colortable[0], (LPBYTE)lpbmhIn + lpbmhIn->biSize, 256 * sizeof(RGBQUAD));
  551. if (lpbmhIn->biCompression == VIDEO_FORMAT_BI_RGB) {
  552. (*lpbmhOut)->biBitCount = 24;
  553. (*lpbmhOut)->biSizeImage = pcvt->ci_dstwidth * pcvt->ci_dstheight * 3;
  554. if (lpbmhIn->biBitCount == 4) {
  555. if (crop_ratio)
  556. *convertproc = (FRAMECONVERTPROC*)&Crop4;
  557. else
  558. *convertproc = (FRAMECONVERTPROC*)&DoHalfSize4;
  559. }
  560. else if (lpbmhIn->biBitCount == 8) {
  561. if (crop_ratio)
  562. *convertproc = (FRAMECONVERTPROC*)&Crop8;
  563. else
  564. *convertproc = (FRAMECONVERTPROC*)&DoHalfSize8;
  565. }
  566. else {
  567. if (crop_ratio)
  568. *convertproc = (FRAMECONVERTPROC*)&Crop;
  569. else
  570. *convertproc = (FRAMECONVERTPROC*)&DoHalfSize;
  571. pcvt->ci_delta = lpbmhIn->biBitCount / 8;
  572. if (lpbmhIn->biBitCount == 16) {
  573. pcvt->ci_Copy = &Copy16;
  574. }
  575. else if (lpbmhIn->biBitCount == 24) {
  576. pcvt->ci_Copy = &Copy24;
  577. }
  578. else if (lpbmhIn->biBitCount == 32) {
  579. pcvt->ci_Copy = &Copy32;
  580. }
  581. }
  582. }
  583. else if (lpbmhIn->biCompression == VIDEO_FORMAT_YVU9) {
  584. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  585. (*lpbmhOut)->biSizeImage = pcvt->ci_dstwidth * pcvt->ci_dstheight + (pcvt->ci_dstwidth * pcvt->ci_dstheight)/8;
  586. if (crop_ratio)
  587. *convertproc = (FRAMECONVERTPROC*)&CropYUVPlanar;
  588. else
  589. *convertproc = (FRAMECONVERTPROC*)&DoHalfSizeYUVPlanar;
  590. pcvt->ci_UVDownSampling = 4;
  591. }
  592. else if ((lpbmhIn->biCompression == VIDEO_FORMAT_YUY2) || (lpbmhIn->biCompression == VIDEO_FORMAT_UYVY)) {
  593. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  594. (*lpbmhOut)->biSizeImage = (DWORD)WIDTHBYTES(pcvt->ci_dstwidth * lpbmhIn->biBitCount) * pcvt->ci_dstheight;
  595. if (crop_ratio)
  596. *convertproc = (FRAMECONVERTPROC*)&CropYUVPacked;
  597. else
  598. *convertproc = (FRAMECONVERTPROC*)&DoHalfSizeYUVPacked;
  599. }
  600. else if ((lpbmhIn->biCompression == VIDEO_FORMAT_I420) || (lpbmhIn->biCompression == VIDEO_FORMAT_IYUV)) {
  601. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  602. (*lpbmhOut)->biSizeImage = (DWORD)WIDTHBYTES(pcvt->ci_dstwidth * lpbmhIn->biBitCount) * pcvt->ci_dstheight;
  603. if (crop_ratio)
  604. *convertproc = (FRAMECONVERTPROC*)&CropYUVPlanar;
  605. else
  606. *convertproc = (FRAMECONVERTPROC*)&DoHalfSizeYUVPlanar;
  607. pcvt->ci_UVDownSampling = 2;
  608. }
  609. *refdata = (LPVOID)pcvt;
  610. return TRUE;
  611. }
  612. else {
  613. if (pcvt)
  614. LocalFree((HANDLE)pcvt);
  615. }
  616. return FALSE;
  617. }
  618. // worker routine to expand an RGB16, RGB24 or RGB32 by copying source into middle of destination
  619. // result is RGB24
  620. BOOL DoBlackBar(
  621. IBitmapSurface* pbsIn,
  622. IBitmapSurface* pbsOut,
  623. PCONVERTINFO refdata
  624. )
  625. {
  626. LPBYTE pBits, pCvtBits, pIn, pOut;
  627. long ipitch, opitch, oextra;
  628. long x, y;
  629. long prelines, postlines, prebytes, postbytes, bytes;
  630. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  631. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  632. prelines = (refdata->ci_dstheight - refdata->ci_height) / 2;
  633. postlines = refdata->ci_dstheight - refdata->ci_height - prelines;
  634. prebytes = (refdata->ci_dstwidth - refdata->ci_width) / 2;
  635. postbytes = (refdata->ci_dstwidth - refdata->ci_width - prebytes) * 3;
  636. prebytes *= 3;
  637. ipitch -= refdata->ci_width * refdata->ci_delta; // bytes at end of each src row
  638. bytes = refdata->ci_dstwidth * 3;
  639. oextra = opitch - bytes + postbytes; // bytes at end of each dst row
  640. pIn = pBits;
  641. pOut = pCvtBits;
  642. // do blank lines at front of destination
  643. for (y = 0; y < prelines; y++) {
  644. ZeroMemory (pOut, bytes);
  645. pOut += opitch;
  646. }
  647. // copy source lines with blank space at front and rear
  648. for (y = 0; y < refdata->ci_height; y++) {
  649. ZeroMemory (pOut, prebytes);
  650. pOut += prebytes;
  651. for (x = 0; x < refdata->ci_width; x++) {
  652. refdata->ci_Copy(&pIn, &pOut);
  653. }
  654. ZeroMemory (pOut, postbytes);
  655. pIn += ipitch;
  656. pOut += oextra;
  657. }
  658. // do blank lines at end of destination
  659. for (y = 0; y < postlines; y++) {
  660. ZeroMemory (pOut, bytes);
  661. pOut += opitch;
  662. }
  663. pbsIn->UnlockBits(NULL, pBits);
  664. pbsOut->UnlockBits(NULL, pCvtBits);
  665. return TRUE;
  666. }
  667. // worker routine to expand an RGB4 by copying source into middle of destination
  668. // result is RGB24
  669. BOOL DoBlackBar4(
  670. IBitmapSurface* pbsIn,
  671. IBitmapSurface* pbsOut,
  672. PCONVERTINFO refdata
  673. )
  674. {
  675. LPBYTE pBits, pCvtBits, pIn, pOut;
  676. long ipitch, opitch, oextra;
  677. long x, y;
  678. long prelines, postlines, prebytes, postbytes, bytes;
  679. BYTE val, pixel;
  680. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  681. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  682. prelines = (refdata->ci_dstheight - refdata->ci_height) / 2;
  683. postlines = refdata->ci_dstheight - refdata->ci_height - prelines;
  684. prebytes = (refdata->ci_dstwidth - refdata->ci_width) / 2;
  685. postbytes = (refdata->ci_dstwidth - refdata->ci_width - prebytes) * 3;
  686. prebytes *= 3;
  687. ipitch -= refdata->ci_width/2; // bytes at end of each src row
  688. bytes = refdata->ci_dstwidth * 3;
  689. oextra = opitch - bytes + postbytes; // bytes at end of each dst row
  690. pIn = pBits;
  691. pOut = pCvtBits;
  692. // do blank lines at front of destination
  693. for (y = 0; y < prelines; y++) {
  694. ZeroMemory (pOut, bytes);
  695. pOut += opitch;
  696. }
  697. // copy source lines with blank space at front and rear
  698. for (y = 0; y < refdata->ci_height; y++) {
  699. ZeroMemory (pOut, prebytes);
  700. pOut += prebytes;
  701. for (x = 0; x < refdata->ci_width/2; x++) {
  702. val = *pIn++;
  703. pixel = (val/16) & 15;
  704. *pOut++ = refdata->ci_colortable[pixel].rgbBlue;
  705. *pOut++ = refdata->ci_colortable[pixel].rgbGreen;
  706. *pOut++ = refdata->ci_colortable[pixel].rgbRed;
  707. pixel = val & 15;
  708. *pOut++ = refdata->ci_colortable[pixel].rgbBlue;
  709. *pOut++ = refdata->ci_colortable[pixel].rgbGreen;
  710. *pOut++ = refdata->ci_colortable[pixel].rgbRed;
  711. }
  712. ZeroMemory (pOut, postbytes);
  713. pIn += ipitch;
  714. pOut += oextra;
  715. }
  716. // do blank lines at end of destination
  717. for (y = 0; y < postlines; y++) {
  718. ZeroMemory (pOut, bytes);
  719. pOut += opitch;
  720. }
  721. pbsIn->UnlockBits(NULL, pBits);
  722. pbsOut->UnlockBits(NULL, pCvtBits);
  723. return TRUE;
  724. }
  725. // worker routine to expand an RGB8 by copying source into middle of destination
  726. // result is RGB24
  727. BOOL DoBlackBar8(
  728. IBitmapSurface* pbsIn,
  729. IBitmapSurface* pbsOut,
  730. PCONVERTINFO refdata
  731. )
  732. {
  733. LPBYTE pBits, pCvtBits, pIn, pOut;
  734. long ipitch, opitch, oextra;
  735. long x, y;
  736. long prelines, postlines, prebytes, postbytes, bytes;
  737. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  738. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  739. prelines = (refdata->ci_dstheight - refdata->ci_height) / 2;
  740. postlines = refdata->ci_dstheight - refdata->ci_height - prelines;
  741. prebytes = (refdata->ci_dstwidth - refdata->ci_width) / 2;
  742. postbytes = (refdata->ci_dstwidth - refdata->ci_width - prebytes) * 3;
  743. prebytes *= 3;
  744. ipitch -= refdata->ci_width; // bytes at end of each src row
  745. bytes = refdata->ci_dstwidth * 3;
  746. oextra = opitch - bytes + postbytes; // bytes at end of each dst row
  747. pIn = pBits;
  748. pOut = pCvtBits;
  749. // do blank lines at front of destination
  750. for (y = 0; y < prelines; y++) {
  751. ZeroMemory (pOut, bytes);
  752. pOut += opitch;
  753. }
  754. // copy source lines with blank space at front and rear
  755. for (y = 0; y < refdata->ci_height; y++) {
  756. ZeroMemory (pOut, prebytes);
  757. pOut += prebytes;
  758. for (x = 0; x < refdata->ci_width; x++) {
  759. *pOut++ = refdata->ci_colortable[*pIn].rgbBlue;
  760. *pOut++ = refdata->ci_colortable[*pIn].rgbGreen;
  761. *pOut++ = refdata->ci_colortable[*pIn++].rgbRed;
  762. }
  763. ZeroMemory (pOut, postbytes);
  764. pIn += ipitch;
  765. pOut += oextra;
  766. }
  767. // do blank lines at end of destination
  768. for (y = 0; y < postlines; y++) {
  769. ZeroMemory (pOut, bytes);
  770. pOut += opitch;
  771. }
  772. pbsIn->UnlockBits(NULL, pBits);
  773. pbsOut->UnlockBits(NULL, pCvtBits);
  774. return TRUE;
  775. }
  776. // worker routine to expand a YVU9 or YUV12 by copying source into middle of destination
  777. // result is YVU9 or YUV12
  778. BOOL DoBlackBarYUVPlanar(
  779. IBitmapSurface* pbsIn,
  780. IBitmapSurface* pbsOut,
  781. PCONVERTINFO refdata
  782. )
  783. {
  784. LPBYTE pBits, pCvtBits;
  785. LONG prelines, postlines, bytesperpixel, prebytes, postbytes, y, bytes;
  786. LONG prelinebytes, postlinebytes;
  787. LPBYTE lpsrc, lpdst;
  788. pbsIn->LockBits(NULL, 0, (void**)&pBits, &bytes);
  789. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &bytes);
  790. lpsrc = pBits;
  791. lpdst = pCvtBits;
  792. // Do the Y component first
  793. prelines = ((refdata->ci_dstheight - refdata->ci_height) / (refdata->ci_UVDownSampling << 1)) * refdata->ci_UVDownSampling;
  794. postlines = refdata->ci_dstheight - refdata->ci_height - prelines;
  795. prebytes = ((refdata->ci_dstwidth - refdata->ci_width) / (refdata->ci_UVDownSampling << 1)) * refdata->ci_UVDownSampling;
  796. postbytes = (refdata->ci_dstwidth - refdata->ci_width - prebytes);
  797. bytes = prelines * refdata->ci_dstwidth + prebytes;
  798. FillMemory (lpdst, bytes, 0x10);
  799. lpdst += bytes;
  800. bytes = refdata->ci_width;
  801. prebytes += postbytes;
  802. for (y=0; y < refdata->ci_height; y++)
  803. {
  804. MoveMemory (lpdst, lpsrc, bytes);
  805. lpsrc += bytes;
  806. lpdst += bytes;
  807. FillMemory (lpdst, prebytes, 0x10);
  808. lpdst += prebytes;
  809. }
  810. // already filled the prebytes of the first postline in loop above
  811. prebytes -= postbytes;
  812. bytes = postlines * refdata->ci_dstwidth - prebytes;
  813. FillMemory (lpdst, bytes, (BYTE)0x10);
  814. lpdst += bytes;
  815. // Do the first color component next
  816. prelines /= refdata->ci_UVDownSampling;
  817. postlines = refdata->ci_dstheight / refdata->ci_UVDownSampling - refdata->ci_height / refdata->ci_UVDownSampling - prelines;
  818. prebytes = prebytes / refdata->ci_UVDownSampling;
  819. postbytes = refdata->ci_dstwidth / refdata->ci_UVDownSampling - refdata->ci_width / refdata->ci_UVDownSampling - prebytes;
  820. prelinebytes = prelines * refdata->ci_dstwidth / refdata->ci_UVDownSampling + prebytes;
  821. FillMemory (lpdst, prelinebytes, 0x80);
  822. lpdst += prelinebytes;
  823. bytes = refdata->ci_width / refdata->ci_UVDownSampling;
  824. prebytes += postbytes;
  825. for (y=0; y < refdata->ci_height / refdata->ci_UVDownSampling; y++)
  826. {
  827. MoveMemory (lpdst, lpsrc, bytes);
  828. lpsrc += bytes;
  829. lpdst += bytes;
  830. FillMemory (lpdst, prebytes, 0x80);
  831. lpdst += prebytes;
  832. }
  833. // already filled the prebytes of the first postline in loop above
  834. postlinebytes = postlines * refdata->ci_dstwidth / refdata->ci_UVDownSampling - (prebytes - postbytes);
  835. FillMemory (lpdst, postlinebytes, 0x80);
  836. lpdst += postlinebytes;
  837. // Do the second color component next
  838. FillMemory (lpdst, prelinebytes, 0x80);
  839. lpdst += prelinebytes;
  840. for (y=0; y < refdata->ci_height / refdata->ci_UVDownSampling; y++)
  841. {
  842. MoveMemory (lpdst, lpsrc, bytes);
  843. lpsrc += bytes;
  844. lpdst += bytes;
  845. FillMemory (lpdst, prebytes, 0x80);
  846. lpdst += prebytes;
  847. }
  848. FillMemory (lpdst, postlinebytes, 0x80);
  849. pbsIn->UnlockBits(NULL, pBits);
  850. pbsOut->UnlockBits(NULL, pCvtBits);
  851. return TRUE;
  852. }
  853. // worker routine to expand a YUV packed DIB by copying source into middle of destination
  854. // result is YUY2 or UYVY
  855. BOOL DoBlackBarYUVPacked(
  856. IBitmapSurface* pbsIn,
  857. IBitmapSurface* pbsOut,
  858. PCONVERTINFO refdata
  859. )
  860. {
  861. LPBYTE pBits, pCvtBits, pIn, pOut;
  862. long ipitch, opitch;
  863. long x, y;
  864. long prelines, postlines, prebytes, postbytes, ibytes, obytes;
  865. pbsIn->LockBits(NULL, 0, (void**)&pBits, &ipitch);
  866. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &opitch);
  867. prelines = (refdata->ci_dstheight - refdata->ci_height) / 2;
  868. postlines = refdata->ci_dstheight - refdata->ci_height - prelines;
  869. prebytes = (refdata->ci_dstwidth - refdata->ci_width) / 2;
  870. postbytes = (refdata->ci_dstwidth - refdata->ci_width - prebytes) / 2;
  871. prebytes /= 2;
  872. ibytes = refdata->ci_width * 2;
  873. obytes = refdata->ci_dstwidth / 2;
  874. pIn = pBits;
  875. pOut = pCvtBits;
  876. // do blank lines at front of destination
  877. for (y = 0; y < prelines; y++) {
  878. for (x = 0; x < obytes; x++) {
  879. *(DWORD *)pOut = refdata->ci_ZeroingDWORD;
  880. pOut += sizeof(DWORD);
  881. }
  882. }
  883. // copy source lines with blank space at front and rear
  884. for (y = 0; y < refdata->ci_height; y++) {
  885. for (x = 0; x < prebytes; x++) {
  886. *(DWORD *)pOut = refdata->ci_ZeroingDWORD;
  887. pOut += sizeof(DWORD);
  888. }
  889. CopyMemory(pOut, pIn, ibytes);
  890. pOut += ibytes;
  891. pIn += ibytes;
  892. for (x = 0; x < postbytes; x++) {
  893. *(DWORD *)pOut = refdata->ci_ZeroingDWORD;
  894. pOut += sizeof(DWORD);
  895. }
  896. }
  897. // do blank lines at end of destination
  898. for (y = 0; y < postlines; y++) {
  899. for (x = 0; x < obytes; x++) {
  900. *(DWORD *)pOut = refdata->ci_ZeroingDWORD;
  901. pOut += sizeof(DWORD);
  902. }
  903. }
  904. pbsIn->UnlockBits(NULL, pBits);
  905. pbsOut->UnlockBits(NULL, pCvtBits);
  906. return TRUE;
  907. }
  908. // routine to prepare for calling blackbar worker routines
  909. // it allocates and initializes a reference data structure
  910. BOOL
  911. InitBlackbar(
  912. LPBITMAPINFOHEADER lpbmhIn,
  913. long desiredwidth,
  914. long desiredheight,
  915. LPBITMAPINFOHEADER *lpbmhOut,
  916. FRAMECONVERTPROC **convertproc,
  917. LPVOID *refdata
  918. )
  919. {
  920. PCONVERTINFO pcvt;
  921. DWORD dwSize;
  922. *convertproc = NULL;
  923. *refdata = NULL;
  924. if ((lpbmhIn->biCompression != VIDEO_FORMAT_BI_RGB) &&
  925. (lpbmhIn->biCompression != VIDEO_FORMAT_YVU9) &&
  926. (lpbmhIn->biCompression != VIDEO_FORMAT_YUY2) &&
  927. (lpbmhIn->biCompression != VIDEO_FORMAT_UYVY) &&
  928. (lpbmhIn->biCompression != VIDEO_FORMAT_I420) &&
  929. (lpbmhIn->biCompression != VIDEO_FORMAT_IYUV))
  930. return FALSE;
  931. // calculate size of convertinfo struct, if we need a colortable, then add 256 entries
  932. // else subtract off the 1 built into the struct definition
  933. dwSize = sizeof(CONVERTINFO) - sizeof(RGBQUAD);
  934. if (lpbmhIn->biBitCount <= 8)
  935. dwSize += 256 * sizeof(RGBQUAD);
  936. // for RGB, YUV input formats, we know that the output format will never need
  937. // an attached color table, so we can allocate lpbmhOut without one
  938. if ((pcvt = (PCONVERTINFO)LocalAlloc(LPTR, dwSize)) &&
  939. (*lpbmhOut = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, lpbmhIn->biSize))) {
  940. CopyMemory(*lpbmhOut, lpbmhIn, lpbmhIn->biSize);
  941. pcvt->ci_width = lpbmhIn->biWidth;
  942. pcvt->ci_height = lpbmhIn->biHeight;
  943. pcvt->ci_dstwidth = desiredwidth;
  944. pcvt->ci_dstheight = desiredheight;
  945. (*lpbmhOut)->biWidth = desiredwidth;
  946. (*lpbmhOut)->biHeight = desiredheight;
  947. // copy colortable from input bitmapinfoheader
  948. if (lpbmhIn->biBitCount <= 8)
  949. CopyMemory(&pcvt->ci_colortable[0], (LPBYTE)lpbmhIn + lpbmhIn->biSize, 256 * sizeof(RGBQUAD));
  950. if (lpbmhIn->biCompression == VIDEO_FORMAT_BI_RGB) {
  951. (*lpbmhOut)->biBitCount = 24;
  952. (*lpbmhOut)->biSizeImage = desiredwidth * desiredheight * 3;
  953. if (lpbmhIn->biBitCount == 4) {
  954. *convertproc = (FRAMECONVERTPROC*)&DoBlackBar4;
  955. }
  956. else if (lpbmhIn->biBitCount == 8) {
  957. *convertproc = (FRAMECONVERTPROC*)&DoBlackBar8;
  958. }
  959. else {
  960. *convertproc = (FRAMECONVERTPROC*)&DoBlackBar;
  961. pcvt->ci_delta = lpbmhIn->biBitCount / 8;
  962. if (lpbmhIn->biBitCount == 16) {
  963. pcvt->ci_Copy = &Copy16;
  964. }
  965. else if (lpbmhIn->biBitCount == 24) {
  966. pcvt->ci_Copy = &Copy24;
  967. }
  968. else if (lpbmhIn->biBitCount == 32) {
  969. pcvt->ci_Copy = &Copy32;
  970. }
  971. }
  972. }
  973. else if (lpbmhIn->biCompression == VIDEO_FORMAT_YVU9) {
  974. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  975. (*lpbmhOut)->biSizeImage = desiredwidth * desiredheight + (desiredwidth * desiredheight)/8;
  976. *convertproc = (FRAMECONVERTPROC*)&DoBlackBarYUVPlanar;
  977. pcvt->ci_UVDownSampling = 4;
  978. }
  979. else if (lpbmhIn->biCompression == VIDEO_FORMAT_YUY2) {
  980. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  981. (*lpbmhOut)->biSizeImage = (DWORD)WIDTHBYTES(desiredwidth * lpbmhIn->biBitCount) * desiredheight;
  982. pcvt->ci_ZeroingDWORD = 0x80108010;
  983. *convertproc = (FRAMECONVERTPROC*)&DoBlackBarYUVPacked;
  984. }
  985. else if (lpbmhIn->biCompression == VIDEO_FORMAT_UYVY) {
  986. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  987. (*lpbmhOut)->biSizeImage = (DWORD)WIDTHBYTES(desiredwidth * lpbmhIn->biBitCount) * desiredheight;
  988. pcvt->ci_ZeroingDWORD = 0x10801080;
  989. *convertproc = (FRAMECONVERTPROC*)&DoBlackBarYUVPacked;
  990. }
  991. else if ((lpbmhIn->biCompression == VIDEO_FORMAT_I420) || (lpbmhIn->biCompression == VIDEO_FORMAT_IYUV)) {
  992. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  993. (*lpbmhOut)->biSizeImage = (DWORD)WIDTHBYTES(desiredwidth * lpbmhIn->biBitCount) * desiredheight;
  994. *convertproc = (FRAMECONVERTPROC*)&DoBlackBarYUVPlanar;
  995. pcvt->ci_UVDownSampling = 2;
  996. }
  997. *refdata = (LPVOID)pcvt;
  998. return TRUE;
  999. }
  1000. else {
  1001. if (pcvt)
  1002. LocalFree((HANDLE)pcvt);
  1003. }
  1004. return FALSE;
  1005. }
  1006. #ifdef ENABLE_ZOOM_CODE
  1007. BOOL Zoom4(
  1008. IBitmapSurface* pbsIn,
  1009. IBitmapSurface* pbsOut,
  1010. PZOOMCONVERTINFO refdata
  1011. )
  1012. {
  1013. return FALSE;
  1014. }
  1015. BOOL Zoom8(
  1016. IBitmapSurface* pbsIn,
  1017. IBitmapSurface* pbsOut,
  1018. PZOOMCONVERTINFO refdata
  1019. )
  1020. {
  1021. return FALSE;
  1022. }
  1023. BOOL Zoom16(
  1024. IBitmapSurface* pbsIn,
  1025. IBitmapSurface* pbsOut,
  1026. PZOOMCONVERTINFO refdata
  1027. )
  1028. {
  1029. return FALSE;
  1030. }
  1031. BOOL Zoom24(
  1032. IBitmapSurface* pbsIn,
  1033. IBitmapSurface* pbsOut,
  1034. PZOOMCONVERTINFO refdata
  1035. )
  1036. {
  1037. LPBYTE pBits, pCvtBits, pIn1, pIn2, pTmp, pOut;
  1038. ROW_VALUES *rptr;
  1039. long i, j, yfac_inv, src_y, src_y_i, q, q1;
  1040. long a;
  1041. pbsIn->LockBits(NULL, 0, (void**)&pBits, &i);
  1042. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &i);
  1043. pOut = pCvtBits;
  1044. yfac_inv = refdata->ci_height * 256 / refdata->ci_dstheight;
  1045. for (i = 0; i < refdata->ci_dstheight; i++) {
  1046. src_y = i * yfac_inv;
  1047. src_y_i = src_y / 256;
  1048. q = src_y - src_y_i * 256;
  1049. q1 = 256 - q;
  1050. rptr = refdata->ci_rptr;
  1051. pIn1 = pBits + src_y_i * refdata->ci_width * 3;
  1052. pIn2 = pIn1 + refdata->ci_width * 3;
  1053. for (j = 0; j < refdata->ci_dstwidth; j++, rptr++) {
  1054. a = rptr->x_i * 3;
  1055. pIn1 += a;
  1056. pIn2 += a;
  1057. a = (((*pIn1) * rptr->p1 + (*(pIn1+3)) * rptr->p) * q1 +
  1058. ((*pIn2) * rptr->p1 + (*(pIn2+3)) * rptr->p) * q) / 256 / 256;
  1059. if (a > 256) a = 255;
  1060. *pOut++ = (BYTE)a; // blue
  1061. pIn1++;
  1062. pIn2++;
  1063. a = (((*pIn1) * rptr->p1 + (*(pIn1+3)) * rptr->p) * q1 +
  1064. ((*pIn2) * rptr->p1 + (*(pIn2+3)) * rptr->p) * q) / 256 / 256;
  1065. if (a > 256) a = 255;
  1066. *pOut++ = (BYTE)a; // green
  1067. pIn1++;
  1068. pIn2++;
  1069. a = (((*pIn1) * rptr->p1 + (*(pIn1+3)) * rptr->p) * q1 +
  1070. ((*pIn2) * rptr->p1 + (*(pIn2+3)) * rptr->p) * q) / 256 / 256;
  1071. if (a > 256) a = 255;
  1072. *pOut++ = (BYTE)a; // red
  1073. pIn1 -= 2;
  1074. pIn2 -= 2;
  1075. }
  1076. }
  1077. pbsIn->UnlockBits(NULL, pBits);
  1078. pbsOut->UnlockBits(NULL, pCvtBits);
  1079. return TRUE;
  1080. }
  1081. BOOL ZoomYVU9(
  1082. IBitmapSurface* pbsIn,
  1083. IBitmapSurface* pbsOut,
  1084. PZOOMCONVERTINFO refdata
  1085. )
  1086. {
  1087. LPBYTE pBits, pCvtBits, pIn1, pIn2, pOut, pOut2, pU1;
  1088. ROW_VALUES *rptr;
  1089. long i, j, yfac_inv, src_y, src_y_i, q, q1;
  1090. long a, b, c, d;
  1091. pbsIn->LockBits(NULL, 0, (void**)&pBits, &i);
  1092. pbsOut->LockBits(NULL, 0, (void**)&pCvtBits, &i);
  1093. pOut = pCvtBits;
  1094. yfac_inv = refdata->ci_height * 256 / refdata->ci_dstheight;
  1095. // Do the Y component first as a bilinear zoom
  1096. for (i = 0; i < refdata->ci_dstheight; i++) {
  1097. src_y = i * yfac_inv;
  1098. src_y_i = src_y / 256;
  1099. q = src_y - src_y_i * 256;
  1100. q1 = 256 - q;
  1101. rptr = refdata->ci_rptr;
  1102. pIn1 = pBits + src_y_i * refdata->ci_width;
  1103. pIn2 = pIn1 + refdata->ci_width;
  1104. for (j = 0; j < refdata->ci_dstwidth; j++, rptr++) {
  1105. pIn1 += rptr->x_i;
  1106. pIn2 += rptr->x_i;
  1107. a = *pIn1;
  1108. b = *(pIn1+1);
  1109. c = *pIn2;
  1110. d = *(pIn2+1);
  1111. a = ((a * rptr->p1 + b * rptr->p) * q1 +
  1112. (c * rptr->p1 + d * rptr->p) * q) / 256 / 256;
  1113. if (a > 256) a = 255;
  1114. *pOut++ = (BYTE)a;
  1115. }
  1116. }
  1117. // Do the V and U components next as a nearest neighbor zoom
  1118. pIn1 = pBits + refdata->ci_width * refdata->ci_height; // start of source V table
  1119. pU1 = pIn1 + (refdata->ci_width * refdata->ci_height) / 16; // start of source U table
  1120. pOut2 = pOut + (refdata->ci_dstwidth * refdata->ci_dstheight) / 16; // start of dest U table
  1121. src_y = 0;
  1122. for (i = 0; i < refdata->ci_dstheight; i += 4) {
  1123. src_y_i = (i * yfac_inv) / 256 / 4;
  1124. d = (src_y_i - src_y) * refdata->ci_width / 4;
  1125. pIn1 += d;
  1126. pU1 += d;
  1127. src_y = src_y_i;
  1128. a = 0;
  1129. rptr = refdata->ci_rptr;
  1130. for (j = 0; j < refdata->ci_dstwidth/4; j++) {
  1131. *pOut++ = *(pIn1+a/4);
  1132. *pOut2++ = *(pU1+a/4);
  1133. a += rptr->x_i;
  1134. rptr++;
  1135. a += rptr->x_i;
  1136. rptr++;
  1137. a += rptr->x_i;
  1138. rptr++;
  1139. a += rptr->x_i;
  1140. rptr++;
  1141. }
  1142. }
  1143. pbsIn->UnlockBits(NULL, pBits);
  1144. pbsOut->UnlockBits(NULL, pCvtBits);
  1145. return TRUE;
  1146. }
  1147. BOOL
  1148. InitScale(
  1149. LPBITMAPINFOHEADER lpbmhIn,
  1150. long desiredwidth,
  1151. long desiredheight,
  1152. LPBITMAPINFOHEADER *lpbmhOut,
  1153. FRAMECONVERTPROC **convertproc,
  1154. LPVOID *refdata
  1155. )
  1156. {
  1157. PZOOMCONVERTINFO pcvt;
  1158. DWORD dwSize, dwBaseSize;
  1159. ROW_VALUES *rptr;
  1160. long i, x, xfac_inv, x_i_last, tmp;
  1161. *convertproc = NULL;
  1162. *refdata = NULL;
  1163. if ((lpbmhIn->biCompression != VIDEO_FORMAT_BI_RGB) &&
  1164. (lpbmhIn->biCompression != VIDEO_FORMAT_YVU9))
  1165. return FALSE;
  1166. // calculate size of zoomconvertinfo struct, if we need a colortable, then add 256 entries
  1167. // else subtract off the 1 built into the struct definition
  1168. dwBaseSize = sizeof(ZOOMCONVERTINFO) - sizeof(RGBQUAD);
  1169. if (lpbmhIn->biBitCount <= 8)
  1170. dwBaseSize += 256 * sizeof(RGBQUAD);
  1171. dwSize = dwBaseSize + desiredwidth * sizeof(ROW_VALUES);
  1172. // for RGB and YVU9 input formats, we know that the output format will never need
  1173. // an attached color table, so we can allocate lpbmhOut without one
  1174. if ((pcvt = (PZOOMCONVERTINFO)LocalAlloc(LPTR, dwSize)) &&
  1175. (*lpbmhOut = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, lpbmhIn->biSize))) {
  1176. CopyMemory(*lpbmhOut, lpbmhIn, lpbmhIn->biSize);
  1177. pcvt->ci_width = lpbmhIn->biWidth;
  1178. pcvt->ci_height = lpbmhIn->biHeight;
  1179. pcvt->ci_dstwidth = desiredwidth;
  1180. pcvt->ci_dstheight = desiredheight;
  1181. (*lpbmhOut)->biWidth = desiredwidth;
  1182. (*lpbmhOut)->biHeight = desiredheight;
  1183. pcvt->ci_rptr = (ROW_VALUES *)(((BYTE *)pcvt) + dwBaseSize);
  1184. rptr = pcvt->ci_rptr;
  1185. xfac_inv = lpbmhIn->biWidth * 256 / desiredwidth;
  1186. x_i_last = 0;
  1187. for (i = 0; i < desiredwidth; i++) {
  1188. x = i * xfac_inv;
  1189. tmp = x / 256;
  1190. rptr->x_i = tmp - x_i_last;
  1191. x_i_last = tmp;
  1192. rptr->p = x - x_i_last * 256;
  1193. rptr->p1 = 256 - rptr->p;
  1194. rptr++;
  1195. }
  1196. // copy colortable from input bitmapinfoheader
  1197. if (lpbmhIn->biBitCount <= 8)
  1198. CopyMemory(&pcvt->ci_colortable[0], (LPBYTE)lpbmhIn + lpbmhIn->biSize, 256 * sizeof(RGBQUAD));
  1199. if (lpbmhIn->biCompression == VIDEO_FORMAT_BI_RGB) {
  1200. (*lpbmhOut)->biBitCount = 24;
  1201. (*lpbmhOut)->biSizeImage = desiredwidth * desiredheight * 3;
  1202. if (lpbmhIn->biBitCount == 4) {
  1203. *convertproc = (FRAMECONVERTPROC*)&Zoom4;
  1204. }
  1205. else if (lpbmhIn->biBitCount == 8) {
  1206. *convertproc = (FRAMECONVERTPROC*)&Zoom8;
  1207. }
  1208. else if (lpbmhIn->biBitCount == 16) {
  1209. *convertproc = (FRAMECONVERTPROC*)&Zoom16;
  1210. }
  1211. else {
  1212. *convertproc = (FRAMECONVERTPROC*)&Zoom24;
  1213. }
  1214. }
  1215. else if (lpbmhIn->biCompression == VIDEO_FORMAT_YVU9) {
  1216. (*lpbmhOut)->biBitCount = lpbmhIn->biBitCount;
  1217. (*lpbmhOut)->biSizeImage = desiredwidth * desiredheight + (desiredwidth * desiredheight)/8;
  1218. *convertproc = (FRAMECONVERTPROC*)&ZoomYVU9;
  1219. }
  1220. *refdata = (LPVOID)pcvt;
  1221. return TRUE;
  1222. }
  1223. else {
  1224. if (pcvt)
  1225. LocalFree((HANDLE)pcvt);
  1226. }
  1227. return FALSE;
  1228. }
  1229. #endif // ENABLE_ZOOM_CODE
  1230. STDMETHODIMP
  1231. CCaptureChain::InitCaptureChain(
  1232. HCAPDEV hcapdev,
  1233. BOOL streaming,
  1234. LPBITMAPINFOHEADER lpcap,
  1235. LONG desiredwidth,
  1236. LONG desiredheight,
  1237. DWORD desiredformat,
  1238. LPBITMAPINFOHEADER *plpdsp
  1239. )
  1240. {
  1241. CFrameOp *ccf;
  1242. CFrameOp *clast;
  1243. CFilterChain *cfilterchain;
  1244. LPBITMAPINFOHEADER lpcvt;
  1245. DWORD lpcapsize;
  1246. FX_ENTRY("CCaptureChain::InitCaptureChain");
  1247. *plpdsp = NULL;
  1248. #ifndef SUPPORT_DESIRED_FORMAT
  1249. if (desiredformat != 0) {
  1250. ERRORMESSAGE(("%s: Invalid desiredformat parameter", _fx_));
  1251. return E_FAIL;
  1252. }
  1253. #endif
  1254. if (streaming) {
  1255. if ((ccf = new CStreamCaptureFrame)) {
  1256. ccf->AddRef();
  1257. if (hcapdev && !((CStreamCaptureFrame*)ccf)->InitCapture(hcapdev, lpcap)) {
  1258. ERRORMESSAGE(("%s: Failed to init capture object", _fx_));
  1259. ccf->Release();
  1260. return E_FAIL;
  1261. }
  1262. }
  1263. }
  1264. else {
  1265. if ((ccf = new CCaptureFrame)) {
  1266. ccf->AddRef();
  1267. if (hcapdev && !((CCaptureFrame*)ccf)->InitCapture(hcapdev, lpcap)) {
  1268. ERRORMESSAGE(("%s: Failed to init capture object", _fx_));
  1269. ccf->Release();
  1270. return E_FAIL;
  1271. }
  1272. }
  1273. }
  1274. if (!ccf) {
  1275. ERRORMESSAGE(("%s: Failed to alloc capture object", _fx_));
  1276. return E_OUTOFMEMORY;
  1277. }
  1278. clast = ccf;
  1279. lpcapsize = lpcap->biSize;
  1280. if (lpcap->biBitCount <= 8)
  1281. lpcapsize += 256 * sizeof(RGBQUAD);
  1282. #if 0
  1283. if ((lpcap->biCompression != BI_RGB) &&
  1284. (lpcap->biCompression != VIDEO_FORMAT_YVU9) &&
  1285. (lpcap->biCompression != VIDEO_FORMAT_INTELI420)) {
  1286. #else
  1287. if ((lpcap->biCompression != BI_RGB) &&
  1288. (lpcap->biCompression != VIDEO_FORMAT_YVU9) &&
  1289. (lpcap->biCompression != VIDEO_FORMAT_YUY2) &&
  1290. (lpcap->biCompression != VIDEO_FORMAT_UYVY) &&
  1291. (lpcap->biCompression != VIDEO_FORMAT_I420) &&
  1292. (lpcap->biCompression != VIDEO_FORMAT_IYUV)) {
  1293. #endif
  1294. // attempt to instantiate an ICM CFrameOp
  1295. CICMcvtFrame *cicm;
  1296. if ((cicm = new CICMcvtFrame)) {
  1297. cicm->AddRef();
  1298. #if 0
  1299. if (cicm->InitCvt(lpcap, lpcapsize, plpdsp, BI_RGB)) {
  1300. #else
  1301. if (cicm->InitCvt(lpcap, lpcapsize, plpdsp)) {
  1302. #endif
  1303. clast->m_next = (CFrameOp*)cicm; // add ICM FrameOp into chain
  1304. clast = (CFrameOp*)cicm;
  1305. }
  1306. else {
  1307. cicm->Release();
  1308. if (!*plpdsp)
  1309. {
  1310. ERRORMESSAGE(("%s: Failed to find a codec", _fx_));
  1311. }
  1312. }
  1313. }
  1314. else
  1315. {
  1316. ERRORMESSAGE(("%s: Failed to alloc codec object", _fx_));
  1317. }
  1318. }
  1319. else if (!*plpdsp) {
  1320. if (*plpdsp = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, lpcapsize))
  1321. CopyMemory(*plpdsp, lpcap, lpcapsize);
  1322. else
  1323. {
  1324. ERRORMESSAGE(("%s: Failed to alloc display bitmapinfoheader", _fx_));
  1325. }
  1326. }
  1327. #ifdef SUPPORT_DESIRED_FORMAT
  1328. #if 0
  1329. // LOOKLOOK RP - this isn't done yet, something to do beyond NM2.0
  1330. if ((desiredformat == VIDEO_FORMAT_INTELI420) &&
  1331. ((*plpdsp)->biCompression != VIDEO_FORMAT_INTELI420)) {
  1332. CConvertFrame *ccvt;
  1333. if (ccvt = new CConvertFrame) {
  1334. ccvt->AddRef();
  1335. if (ccvt->InitConverter(lpcvt, convertproc, refdata)) {
  1336. LocalFree((HANDLE)*plpdsp);
  1337. *plpdsp = lpcvt;
  1338. clast->m_next = (CFrameOp*)ccvt; // add FrameOp into chain
  1339. clast = (CFrameOp*)ccvt;
  1340. }
  1341. else
  1342. ccvt->Release();
  1343. }
  1344. }
  1345. #endif
  1346. #if 0
  1347. if (((desiredformat == VIDEO_FORMAT_YVU9) &&
  1348. ((*plpdsp)->biCompression != VIDEO_FORMAT_YVU9)) ||
  1349. ((desiredformat == VIDEO_FORMAT_INTELI420) &&
  1350. ((*plpdsp)->biCompression != VIDEO_FORMAT_INTELI420))) {
  1351. #else
  1352. if (((desiredformat == VIDEO_FORMAT_YVU9) &&
  1353. ((*plpdsp)->biCompression != VIDEO_FORMAT_YVU9)) ||
  1354. ((desiredformat == VIDEO_FORMAT_YUY2) &&
  1355. ((*plpdsp)->biCompression != VIDEO_FORMAT_YUY2)) ||
  1356. ((desiredformat == VIDEO_FORMAT_UYVY) &&
  1357. ((*plpdsp)->biCompression != VIDEO_FORMAT_UYVY)) ||
  1358. ((desiredformat == VIDEO_FORMAT_I420) &&
  1359. ((*plpdsp)->biCompression != VIDEO_FORMAT_I420)) ||
  1360. ((desiredformat == VIDEO_FORMAT_IYUV) &&
  1361. ((*plpdsp)->biCompression != VIDEO_FORMAT_IYUV))) {
  1362. #endif
  1363. // attempt to instantiate an ICM CFrameOp
  1364. CICMcvtFrame *cicm;
  1365. if ((cicm = new CICMcvtFrame)) {
  1366. cicm->AddRef();
  1367. if (cicm->InitCvt(*plpdsp, lpcapsize, &lpcvt, desiredformat)) {
  1368. clast->m_next = (CFrameOp*)cicm; // add ICM FrameOp into chain
  1369. clast = (CFrameOp*)cicm;
  1370. LocalFree((HANDLE)*plpdsp);
  1371. *plpdsp = lpcvt;
  1372. }
  1373. else {
  1374. cicm->Release();
  1375. if (!*plpdsp)
  1376. {
  1377. ERRORMESSAGE(("%s: Failed to find a codec", _fx_));
  1378. }
  1379. }
  1380. }
  1381. else
  1382. {
  1383. ERRORMESSAGE(("%s: Failed to alloc codec object", _fx_));
  1384. }
  1385. }
  1386. #endif // SUPPORT_DESIRED_FORMAT
  1387. {
  1388. CConvertFrame *ccvt;
  1389. FRAMECONVERTPROC *convertproc;
  1390. LPVOID refdata;
  1391. #ifdef ENABLE_ZOOM_CODE
  1392. BOOL attemptzoom;
  1393. attemptzoom = TRUE;
  1394. #endif
  1395. while (*plpdsp && (((*plpdsp)->biWidth != desiredwidth) ||
  1396. ((*plpdsp)->biHeight != desiredheight) ||
  1397. (((*plpdsp)->biCompression == BI_RGB) && ((*plpdsp)->biBitCount <= 8)))) {
  1398. lpcvt = NULL;
  1399. #ifdef ENABLE_ZOOM_CODE
  1400. if (attemptzoom) {
  1401. InitScale(*plpdsp, desiredwidth, desiredheight, &lpcvt, &convertproc, &refdata);
  1402. attemptzoom = FALSE;
  1403. }
  1404. #endif
  1405. if (!lpcvt) {
  1406. if (((*plpdsp)->biWidth >= desiredwidth) && ((*plpdsp)->biHeight >= desiredheight)) {
  1407. // try to shrink
  1408. InitShrink(*plpdsp, desiredwidth, desiredheight, &lpcvt, &convertproc, &refdata);
  1409. }
  1410. else {
  1411. // try to blackbar
  1412. InitBlackbar(*plpdsp, desiredwidth, desiredheight, &lpcvt, &convertproc, &refdata);
  1413. }
  1414. }
  1415. if (lpcvt) {
  1416. if (ccvt = new CConvertFrame) {
  1417. ccvt->AddRef();
  1418. if (ccvt->InitConverter(lpcvt, convertproc, refdata)) {
  1419. LocalFree((HANDLE)*plpdsp);
  1420. *plpdsp = lpcvt;
  1421. clast->m_next = (CFrameOp*)ccvt; // add FrameOp into chain
  1422. clast = (CFrameOp*)ccvt;
  1423. continue;
  1424. }
  1425. else
  1426. ccvt->Release();
  1427. }
  1428. }
  1429. else {
  1430. ERRORMESSAGE(("%s: Can't convert", _fx_));
  1431. LocalFree((HANDLE)*plpdsp);
  1432. *plpdsp = NULL;
  1433. }
  1434. }
  1435. }
  1436. if (*plpdsp) {
  1437. // allocate a placeholder for a filter chain
  1438. if (cfilterchain = new CFilterChain) {
  1439. cfilterchain->AddRef();
  1440. // placeholder needs reference to a pool to pass to added filters
  1441. if (clast->m_pool && clast->m_pool->Growable()) {
  1442. cfilterchain->m_pool = clast->m_pool;
  1443. cfilterchain->m_pool->AddRef();
  1444. }
  1445. else {
  1446. if ((cfilterchain->m_pool = new CVidPool)) {
  1447. cfilterchain->m_pool->AddRef();
  1448. if (cfilterchain->m_pool->InitPool(2, *plpdsp) != NO_ERROR) {
  1449. ERRORMESSAGE(("%s: Failed to init filter pool", _fx_));
  1450. cfilterchain->m_pool->Release();
  1451. cfilterchain->m_pool = NULL;
  1452. }
  1453. }
  1454. else
  1455. {
  1456. ERRORMESSAGE(("%s: Failed to alloc filter pool", _fx_));
  1457. }
  1458. }
  1459. if (cfilterchain->m_pool) {
  1460. clast->m_next = (CFrameOp*)cfilterchain; // add placeholder FrameOp into chain
  1461. clast = (CFrameOp*)cfilterchain;
  1462. }
  1463. else {
  1464. cfilterchain->Release();
  1465. cfilterchain = NULL;
  1466. }
  1467. }
  1468. if (m_opchain)
  1469. m_opchain->Release();
  1470. m_opchain = ccf;
  1471. m_filterchain = cfilterchain;
  1472. return NO_ERROR;
  1473. }
  1474. ccf->Release(); // discard partial chain
  1475. return E_FAIL;
  1476. }
  1477. // AddFilter
  1478. // Adds a filter to the chain. If hAfter is NULL, the filter is added
  1479. // to the head of the chain.
  1480. STDMETHODIMP
  1481. CCaptureChain::AddFilter(
  1482. CLSID* pclsid,
  1483. LPBITMAPINFOHEADER lpbmhIn,
  1484. HANDLE* phNew,
  1485. HANDLE hAfter
  1486. )
  1487. {
  1488. HRESULT hres;
  1489. IBitmapEffect *effect;
  1490. CFilterFrame *cff;
  1491. CFilterChain *chain;
  1492. CFilterFrame *previous;
  1493. if (m_filterchain) {
  1494. m_filterchain->AddRef(); // lock chain from destruction
  1495. // find insertion point
  1496. previous = m_filterchain->m_head;
  1497. if (hAfter) {
  1498. while (previous && (previous->m_tag != hAfter))
  1499. previous = (CFilterFrame*)previous->m_next;
  1500. if (!previous) {
  1501. // can't find hAfter, so fail call
  1502. m_filterchain->Release(); // unlock m_filterchain
  1503. return E_INVALIDARG;
  1504. }
  1505. }
  1506. // load, init and link in new filter
  1507. if (cff = new CFilterFrame) {
  1508. cff->AddRef();
  1509. if ((hres = LoadFilter(pclsid, &effect)) == NO_ERROR) {
  1510. m_filterchain->m_pool->AddRef();
  1511. if (cff->InitFilter(effect, lpbmhIn, m_filterchain->m_pool))
  1512. hres = NO_ERROR;
  1513. else
  1514. hres = E_OUTOFMEMORY;
  1515. m_filterchain->m_pool->Release();
  1516. if (hres == NO_ERROR) {
  1517. cff->m_clsid = *pclsid;
  1518. cff->m_tag = (HANDLE)(++m_filtertags);
  1519. if (phNew)
  1520. *phNew = (HANDLE)cff->m_tag;
  1521. EnterCriticalSection(&m_capcs);
  1522. if (previous) {
  1523. cff->m_next = previous->m_next;
  1524. previous->m_next = cff;
  1525. }
  1526. else {
  1527. cff->m_next = m_filterchain->m_head;
  1528. m_filterchain->m_head = cff;
  1529. }
  1530. LeaveCriticalSection(&m_capcs);
  1531. m_filterchain->Release();
  1532. return NO_ERROR;
  1533. }
  1534. }
  1535. cff->Release();
  1536. }
  1537. else
  1538. hres = E_OUTOFMEMORY;
  1539. m_filterchain->Release(); // unlock m_filterchain
  1540. return hres;
  1541. }
  1542. return E_UNEXPECTED;
  1543. }
  1544. STDMETHODIMP
  1545. CCaptureChain::RemoveFilter(
  1546. HANDLE hFilter
  1547. )
  1548. {
  1549. return E_NOTIMPL;
  1550. }
  1551. STDMETHODIMP
  1552. CCaptureChain::DisplayFilterProperties(
  1553. HANDLE hFilter,
  1554. HWND hwndParent
  1555. )
  1556. {
  1557. return E_NOTIMPL;
  1558. }