vid_overlay.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. #include "main.h"
  2. #include <multimon.h>
  3. #include "vid_overlay.h"
  4. #include "vid_subs.h"
  5. #include "directdraw.h"
  6. #include "WinampAttributes.h"
  7. #include "../nsutil/image.h"
  8. #include <api.h>
  9. OverlayVideoOutput overlayVideo;
  10. extern "C" void getViewport(RECT *r, HWND wnd, int full, RECT *sr);
  11. #if 0
  12. #include <math.h>
  13. _inline long int lrintf(float flt)
  14. {
  15. int intgr;
  16. _asm
  17. {
  18. fld flt
  19. fistp intgr
  20. }
  21. return intgr;
  22. }
  23. static float clip(float x, float a, float b)
  24. {
  25. float x1 = fabs(x - a);
  26. float x2 = fabs(x - b);
  27. x = x1 + (a + b);
  28. x -= x2;
  29. x *= 0.5f;
  30. return (x);
  31. }
  32. void DoGamma(YV12_PLANES *planes, int height)
  33. {
  34. if (config_video_brightness != 128 || config_video_contrast != 128)
  35. {
  36. int x, y = height * planes->y.rowBytes;
  37. float add = config_video_brightness - 128;
  38. float mult = config_video_contrast / 128.f;
  39. unsigned char *pix = planes->y.baseAddr;
  40. for (x = 0; x < y; x++)
  41. {
  42. float value = (float) * pix;
  43. value = clip(value * mult + add, 0.0f, 255.0f);
  44. *pix++ = lrintf(value);
  45. }
  46. }
  47. }
  48. #else
  49. #define DoGamma(a,b)
  50. #endif
  51. void YV12_to_YUY2(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip)
  52. {
  53. const unsigned char *yi = planes->y.baseAddr;
  54. const unsigned char *ui = planes->u.baseAddr;
  55. const unsigned char *vi = planes->v.baseAddr;
  56. if (flip)
  57. output += pitch * (height - 1);
  58. while (height > 0)
  59. {
  60. int x = width;
  61. unsigned char *oo = output;
  62. while (x > 0)
  63. {
  64. output[0] = *yi++; output[1] = *ui++; output[2] = *yi++; output[3] = *vi++;
  65. output += 4; x -= 2;
  66. }
  67. ui -= width / 2;
  68. vi -= width / 2;
  69. yi += planes->y.rowBytes - width;
  70. x = width;
  71. if (flip) output = oo - pitch;
  72. else output += pitch - width * 2;
  73. oo = output;
  74. while (x > 0)
  75. {
  76. output[0] = *yi++; output[1] = *ui++; output[2] = *yi++; output[3] = *vi++;
  77. output += 4; x -= 2;
  78. }
  79. if (flip) output = oo - pitch;
  80. else output += pitch - width * 2;
  81. ui += planes->u.rowBytes - (width / 2);
  82. vi += planes->v.rowBytes - (width / 2);
  83. yi += planes->y.rowBytes - width;
  84. height -= 2;
  85. }
  86. }
  87. void YV12_to_UYVY(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip)
  88. {
  89. const unsigned char *yi = planes->y.baseAddr;
  90. const unsigned char *ui = planes->u.baseAddr;
  91. const unsigned char *vi = planes->v.baseAddr;
  92. if (flip) output += pitch * (height - 1);
  93. while (height > 0)
  94. {
  95. int x = width;
  96. unsigned char *oo = output;
  97. while (x > 0)
  98. {
  99. output[0] = *ui++; output[1] = *yi++; output[2] = *vi++; output[3] = *yi++;
  100. output += 4; x -= 2;
  101. }
  102. ui -= width / 2;
  103. vi -= width / 2;
  104. yi += planes->y.rowBytes - width;
  105. x = width;
  106. if (flip) output = oo - pitch;
  107. else output += pitch - width * 2;
  108. oo = output;
  109. while (x > 0)
  110. {
  111. output[0] = *ui++; output[1] = *yi++; output[2] = *vi++; output[3] = *yi++;
  112. output += 4; x -= 2;
  113. }
  114. if (flip) output = oo - pitch;
  115. else output += pitch - width * 2;
  116. ui += planes->u.rowBytes - (width / 2);
  117. vi += planes->v.rowBytes - (width / 2);
  118. yi += planes->y.rowBytes - width;
  119. height -= 2;
  120. }
  121. }
  122. void YV12_to_YV12(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip)
  123. { // woo native YV12 copy
  124. if (flip)
  125. {
  126. nsutil_image_CopyFlipped_U8(output, pitch, planes->y.baseAddr, planes->y.rowBytes, width, height);
  127. unsigned char *o = output + height * pitch;
  128. nsutil_image_CopyFlipped_U8(o, pitch/2, planes->v.baseAddr, planes->v.rowBytes, width/2, height/2);
  129. o = output + (height * pitch) + (height/2) * (pitch/2); // benski> because height might be an odd number, it is important NOT to simplify this equation!
  130. nsutil_image_CopyFlipped_U8(o, pitch/2, planes->u.baseAddr, planes->u.rowBytes, width/2, height/2);
  131. }
  132. else
  133. {
  134. nsutil_image_Copy_U8(output, pitch, planes->y.baseAddr, planes->y.rowBytes, width, height);
  135. unsigned char *o = output + height * pitch;
  136. nsutil_image_Copy_U8(o, pitch/2, planes->v.baseAddr, planes->v.rowBytes, width/2, height/2);
  137. o = output + (height * pitch) + (height/2) * (pitch/2); // benski> because height might be an odd number, it is important NOT to simplify this equation!
  138. nsutil_image_Copy_U8(o, pitch/2, planes->u.baseAddr, planes->u.rowBytes, width/2, height/2);
  139. }
  140. }
  141. void YUY2_to_YUY2(unsigned char *output, const char *buf, int pitch, int width, int height, int flip)
  142. {
  143. const char *a = buf;
  144. unsigned char *b = output;
  145. int l = width * 2, l2 = pitch;
  146. if (flip)
  147. {
  148. b += (height - 1) * l2;
  149. l2 = -l2;
  150. }
  151. //wee straight YUY2 copy
  152. for (int i = 0;i < height;i++)
  153. {
  154. memcpy(b, a, l);
  155. b += l2;
  156. a += l;
  157. }
  158. }
  159. void YUY2_to_UYVY(unsigned char *output, const char *buf, int pitch, int width, int height, int flip)
  160. {
  161. const char *a = buf;
  162. unsigned char *b = output;
  163. int l = width * 2, l2 = pitch;
  164. if (flip)
  165. {
  166. b += (height - 1) * l2;
  167. l2 = -l2;
  168. }
  169. for (int i = 0;i < height;i++)
  170. {
  171. int x = width / 2;
  172. while (x-- > 0)
  173. {
  174. b[0] = a[1];
  175. b[1] = a[0];
  176. b[2] = a[3];
  177. b[3] = a[2];
  178. a += 4;
  179. b += 4;
  180. }
  181. memcpy(b, a, l);
  182. b += l2;
  183. a += l;
  184. }
  185. }
  186. #define INIT_DIRECTDRAW_STRUCT(x) (ZeroMemory(&x, sizeof(x)), x.dwSize=sizeof(x))
  187. // I like to set these to 255,0,255 to test that we arent drawing this color too many playces
  188. #define OV_COL_R 16
  189. #define OV_COL_G 0
  190. #define OV_COL_B 16
  191. OverlayVideoOutput::OverlayVideoOutput()
  192. {
  193. lpDD = NULL;
  194. m_closed = 0;
  195. overlay_color = RGB(OV_COL_R, OV_COL_G, OV_COL_B);
  196. lpddsOverlay = NULL;
  197. lpddsPrimary = NULL;
  198. lpBackBuffer = NULL;
  199. width = height = flip = 0;
  200. type = VIDEO_MAKETYPE('Y', 'V', '1', '2');
  201. uDestSizeAlign = 0;
  202. uSrcSizeAlign = 0;
  203. dwUpdateFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
  204. curSubtitle = NULL;
  205. yuy2_output = uyvy_output = 0;
  206. initing = false;
  207. needchange = 0;
  208. memset(&m_oldrd, 0, sizeof(m_oldrd));
  209. memset(&winRect, 0, sizeof(winRect));
  210. subFont = NULL;
  211. m_fontsize = 0;
  212. resetSubtitle();
  213. }
  214. OverlayVideoOutput::~OverlayVideoOutput()
  215. {
  216. OverlayVideoOutput::close();
  217. }
  218. static DWORD DD_ColorMatch(LPDIRECTDRAWSURFACE pdds, COLORREF rgb)
  219. {
  220. COLORREF rgbT = CLR_INVALID;
  221. HDC hdc;
  222. DWORD dw = CLR_INVALID;
  223. DDSURFACEDESC ddsd;
  224. HRESULT hres;
  225. //
  226. // use GDI SetPixel to color match for us
  227. //
  228. if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
  229. {
  230. rgbT = GetPixel(hdc, 0, 0); // save current pixel value
  231. SetPixel(hdc, 0, 0, rgb); // set our value
  232. pdds->ReleaseDC(hdc);
  233. }
  234. // now lock the surface so we can read back the converted color
  235. ddsd.dwSize = sizeof(ddsd);
  236. while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) ==
  237. DDERR_WASSTILLDRAWING)
  238. ;
  239. if (hres == DD_OK)
  240. {
  241. dw = *(DWORD *)ddsd.lpSurface; // get DWORD
  242. if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
  243. dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; // mask it to bpp
  244. pdds->Unlock(NULL);
  245. }
  246. // now put the color that was there back.
  247. if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
  248. {
  249. SetPixel(hdc, 0, 0, rgbT);
  250. pdds->ReleaseDC(hdc);
  251. }
  252. return dw;
  253. }
  254. int OverlayVideoOutput::create(HWND parent, VideoAspectAdjuster *_adjuster, int w, int h, unsigned int ptype, int flipit, double aspectratio)
  255. {
  256. OverlayVideoOutput::close();
  257. this->parent = parent;
  258. type = ptype;
  259. width = w;
  260. height = h;
  261. flip = flipit;
  262. adjuster = _adjuster;
  263. initing = true;
  264. HWND hwnd = this->parent;
  265. if (lpDD) lpDD->Release();
  266. lpDD = NULL;
  267. update_monitor_coords();
  268. if (_DirectDrawCreate)
  269. {
  270. if (!foundGUID) _DirectDrawCreate(NULL, &lpDD, NULL);
  271. else _DirectDrawCreate(&m_devguid, &lpDD, NULL);
  272. }
  273. if (!lpDD)
  274. {
  275. initing = false;
  276. return 0;
  277. }
  278. lpDD->SetCooperativeLevel(hwnd, DDSCL_NOWINDOWCHANGES | DDSCL_NORMAL);
  279. DDSURFACEDESC ddsd;
  280. INIT_DIRECTDRAW_STRUCT(ddsd);
  281. ddsd.dwFlags = DDSD_CAPS;
  282. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  283. lpDD->CreateSurface(&ddsd, &lpddsPrimary, NULL);
  284. if (!lpddsPrimary)
  285. {
  286. if (lpDD) lpDD->Release();
  287. lpDD = NULL;
  288. initing = false;
  289. return 0;
  290. }
  291. // init overlay
  292. DDSURFACEDESC ddsdOverlay;
  293. INIT_DIRECTDRAW_STRUCT(ddsdOverlay);
  294. ddsdOverlay.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  295. ddsdOverlay.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_BACKBUFFERCOUNT;
  296. ddsdOverlay.dwBackBufferCount = 1;
  297. ddsdOverlay.dwWidth = w;
  298. ddsdOverlay.dwHeight = h;
  299. ddsdOverlay.lPitch = w * 4;
  300. DDPIXELFORMAT pf[] =
  301. {
  302. {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0},
  303. {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0}, // UYVY
  304. {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0},
  305. // TODO:
  306. // {sizeof(DDPIXELFORMAT), DDPF_FOURCC | DDPF_YUV, MAKEFOURCC('N','V','1','2'), 12, 0, 0, 0, 0}, // NV12
  307. // {sizeof(DDPIXELFORMAT), DDPF_RGB,0,16,0xf800,0x07e0,0x001f,0} // RGB565
  308. };
  309. int tab[5];
  310. if (type == VIDEO_MAKETYPE('Y', 'U', 'Y', '2'))
  311. {
  312. tab[0] = 0; // default is YUY2
  313. tab[1] = 1;
  314. tab[2] = -1;
  315. }
  316. else if (type == VIDEO_MAKETYPE('U', 'Y', 'V', 'Y'))
  317. {
  318. tab[0] = 1; // make UYVY default
  319. tab[1] = 0;
  320. tab[2] = -1;
  321. }
  322. else if (type == VIDEO_MAKETYPE('Y', 'V', '1', '2'))
  323. {
  324. if (config_video_yv12)
  325. {
  326. tab[0] = 2;
  327. tab[1] = 0;
  328. tab[2] = 1;
  329. tab[3] = -1;
  330. }
  331. else
  332. {
  333. //use YUY2
  334. tab[0] = 0; // default is YUY2
  335. tab[1] = 1;
  336. tab[2] = -1;
  337. }
  338. }
  339. else
  340. {
  341. tab[0] = -1; // default is RGB
  342. }
  343. int x = 4096;
  344. HRESULT v = -1;
  345. for (x = 0; x < sizeof(tab) / sizeof(tab[0]) && tab[x] >= 0; x ++)
  346. {
  347. ddsdOverlay.ddpfPixelFormat = pf[tab[x]];
  348. v = lpDD->CreateSurface(&ddsdOverlay, &lpddsOverlay, NULL);
  349. if (!FAILED(v)) break;
  350. }
  351. if (FAILED(v) || x >= sizeof(tab) / sizeof(tab[0]) || tab[x] < 0)
  352. {
  353. initing = false;
  354. return 0;
  355. }
  356. yuy2_output = (tab[x] == 0);
  357. uyvy_output = (tab[x] == 1);
  358. //get the backbuffer surface
  359. DDSCAPS ddscaps;
  360. ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  361. v = lpddsOverlay->GetAttachedSurface(&ddscaps, &lpBackBuffer);
  362. if (v != DD_OK || lpBackBuffer == 0)
  363. {
  364. //FUCKO: make it use normal vsync
  365. lpBackBuffer = 0;
  366. initing = FALSE;
  367. return 0;
  368. }
  369. INIT_DIRECTDRAW_STRUCT(capsDrv);
  370. lpDD->GetCaps(&capsDrv, NULL);
  371. uDestSizeAlign = capsDrv.dwAlignSizeDest;
  372. uSrcSizeAlign = capsDrv.dwAlignSizeSrc;
  373. dwUpdateFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
  374. DEVMODE d;
  375. d.dmSize = sizeof(d);
  376. d.dmDriverExtra = 0;
  377. EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &d);
  378. int rv = OV_COL_R, gv = OV_COL_G, bv = OV_COL_B;
  379. overlay_color = RGB(rv, gv, bv);
  380. if (d.dmBitsPerPel == 8)
  381. {
  382. overlay_color = RGB(255, 0, 255);
  383. }
  384. INIT_DIRECTDRAW_STRUCT(ovfx);
  385. ovfx.dwDDFX = 0;
  386. switch (d.dmBitsPerPel)
  387. {
  388. case 8:
  389. ovfx.dckDestColorkey.dwColorSpaceLowValue = 253;
  390. break;
  391. case 16:
  392. ovfx.dckDestColorkey.dwColorSpaceLowValue = ((rv >> 3) << 11) | ((gv >> 2) << 5) | (bv >> 3);
  393. break;
  394. case 15:
  395. ovfx.dckDestColorkey.dwColorSpaceLowValue = ((rv >> 3) << 10) | ((gv >> 3) << 5) | (bv >> 3);
  396. break;
  397. case 24: case 32:
  398. ovfx.dckDestColorkey.dwColorSpaceLowValue = (rv << 16) | (gv << 8) | bv;
  399. break;
  400. }
  401. //try to get the correct bit depth thru directdraw (for fucked up 16 bits displays for ie.)
  402. {
  403. DDSURFACEDESC DDsd = {sizeof(DDsd), };
  404. lpddsPrimary->GetSurfaceDesc(&ddsd);
  405. DDsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; //create the surface at screen depth
  406. DDsd.dwWidth = 8;
  407. DDsd.dwHeight = 8;
  408. DDsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY;
  409. LPDIRECTDRAWSURFACE tempsurf;
  410. if (lpDD->CreateSurface(&DDsd, &tempsurf, NULL) == DD_OK)
  411. {
  412. int res = DD_ColorMatch(tempsurf, overlay_color);
  413. if (res != CLR_INVALID) ovfx.dckDestColorkey.dwColorSpaceLowValue = res;
  414. tempsurf->Release();
  415. }
  416. }
  417. ovfx.dckDestColorkey.dwColorSpaceHighValue = ovfx.dckDestColorkey.dwColorSpaceLowValue;
  418. getRects(&rs, &rd);
  419. if (FAILED(lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx)))
  420. {
  421. initing = false;
  422. return 0;
  423. }
  424. initing = false;
  425. DDSURFACEDESC dd = {sizeof(dd), };
  426. if (lpddsOverlay->Lock(NULL, &dd, DDLOCK_WAIT, NULL) != DD_OK) return 0;
  427. unsigned char *o = (unsigned char*)dd.lpSurface;
  428. if (uyvy_output || yuy2_output)
  429. {
  430. int x = dd.lPitch * height / 2;
  431. while (x--)
  432. {
  433. if (uyvy_output)
  434. {
  435. *o++ = 128;
  436. *o++ = 0;
  437. }
  438. else
  439. {
  440. *o++ = 0;
  441. *o++ = -128;
  442. }
  443. }
  444. }
  445. else
  446. {
  447. memset(o, 0, dd.lPitch*height); o += dd.lPitch * height;
  448. memset(o, 128, dd.lPitch*height / 2);
  449. }
  450. lpddsOverlay->Unlock(&dd);
  451. m_closed = 0;
  452. needchange = 0;
  453. InvalidateRect(hwnd, NULL, TRUE);
  454. return 1;
  455. }
  456. void OverlayVideoOutput::close()
  457. {
  458. m_closed = 1;
  459. if (lpddsOverlay) lpddsOverlay->UpdateOverlay(NULL, lpddsPrimary, NULL, DDOVER_HIDE , NULL);
  460. if (lpBackBuffer) lpBackBuffer->Release(); lpBackBuffer = 0;
  461. if (lpddsOverlay) lpddsOverlay->Release(); lpddsOverlay = 0;
  462. if (lpddsPrimary) lpddsPrimary->Release(); lpddsPrimary = 0;
  463. if (lpDD) lpDD->Release(); lpDD = 0; // BU added NULL check in response to talkback
  464. if (subFont) DeleteObject(subFont); subFont = 0;
  465. }
  466. void OverlayVideoOutput::getRects(RECT *drs, RECT *drd, int fixmultimon) const
  467. {
  468. //if(GetParent(hwnd)) hwnd=GetParent(hwnd);
  469. RECT rd, rs;
  470. GetClientRect(parent, &rd);
  471. ClientToScreen(parent, (LPPOINT)&rd);
  472. ClientToScreen(parent, ((LPPOINT)&rd) + 1);
  473. adjuster->adjustAspect(rd);
  474. rd.left -= m_mon_x;
  475. rd.right -= m_mon_x;
  476. rd.top -= m_mon_y;
  477. rd.bottom -= m_mon_y;
  478. memset(&rs, 0, sizeof(rs));
  479. rs.right = width;
  480. rs.bottom = height;
  481. if (fixmultimon)
  482. {
  483. //resize overlay for off-screen
  484. RECT rfull;
  485. getViewport(&rfull, parent, 1, NULL);
  486. rfull.left -= m_mon_x;
  487. rfull.right -= m_mon_x;
  488. rfull.top -= m_mon_y;
  489. rfull.bottom -= m_mon_y;
  490. if (rd.right > rfull.right)
  491. {
  492. int diff = rd.right - rfull.right;
  493. float sc = (float)(width) / (float)(rd.right - rd.left);
  494. rd.right = rfull.right;
  495. rs.right = width - (int)(diff * sc);
  496. }
  497. if (rd.left < rfull.left)
  498. {
  499. int diff = rfull.left - rd.left;
  500. float sc = (float)(width) / (float)(rd.right - rd.left);
  501. rd.left = rfull.left;
  502. rs.left = (int)(diff * sc);
  503. }
  504. if (rd.bottom > rfull.bottom)
  505. {
  506. int diff = rd.bottom - rfull.bottom;
  507. float sc = (float)(height) / (float)(rd.bottom - rd.top);
  508. rd.bottom = rfull.bottom;
  509. rs.bottom = height - (int)(diff * sc);
  510. }
  511. if (rd.top < rfull.top)
  512. {
  513. int diff = rfull.top - rd.top;
  514. float sc = (float)(height) / (float)(rd.bottom - rd.top);
  515. rd.top = rfull.top;
  516. rs.top = (int)(diff * sc);
  517. }
  518. }
  519. if (capsDrv.dwCaps & DDCAPS_ALIGNSIZESRC && uDestSizeAlign)
  520. {
  521. rs.left = (int)((rs.left + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
  522. rs.right = (int)((rs.right + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
  523. }
  524. if (capsDrv.dwCaps & DDCAPS_ALIGNSIZEDEST && uDestSizeAlign)
  525. {
  526. rd.left = (int)((rd.left + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
  527. rd.right = (int)((rd.right + uDestSizeAlign - 1) / uDestSizeAlign) * uDestSizeAlign;
  528. }
  529. *drd = rd;
  530. *drs = rs;
  531. }
  532. void OverlayVideoOutput::timerCallback()
  533. {
  534. if (!adjuster)
  535. return ;
  536. RECT rd, rs;
  537. getRects(&rs, &rd);
  538. if (memcmp(&m_oldrd, &rd, sizeof(RECT)))
  539. {
  540. if ((m_oldrd.right - m_oldrd.left) != (rd.right - rd.left) || (m_oldrd.bottom - m_oldrd.top) != (rd.bottom - rd.top))
  541. {
  542. resetSubtitle();
  543. }
  544. m_oldrd = rd;
  545. if (!initing && lpddsOverlay)
  546. if (FAILED(lpddsOverlay->UpdateOverlay(&rs, lpddsPrimary, &rd, dwUpdateFlags, &ovfx)))
  547. {
  548. needchange = 1;
  549. }
  550. InvalidateRect(parent, NULL, FALSE);
  551. }
  552. }
  553. int OverlayVideoOutput::onPaint(HWND hwnd)
  554. {
  555. PAINTSTRUCT p;
  556. BeginPaint(hwnd, &p);
  557. if (!m_closed)
  558. {
  559. RECT r, rs, rfull, clientRect;
  560. RECT drawRect;
  561. getRects(&rs, &r, 0); // we don't just fill the entire client rect, cause that looks gross
  562. getViewport(&rfull, hwnd, 1, NULL);
  563. // go from this screen coords to global coords
  564. r.left += rfull.left;
  565. r.top += rfull.top;
  566. r.right += rfull.left;
  567. r.bottom += rfull.top;
  568. // go from global back to client
  569. ScreenToClient(hwnd, (LPPOINT)&r);
  570. ScreenToClient(hwnd, ((LPPOINT)&r) + 1);
  571. HBRUSH br = (HBRUSH) GetStockObject(BLACK_BRUSH);
  572. GetClientRect(hwnd, &clientRect);
  573. // left black box
  574. drawRect.left = clientRect.left;
  575. drawRect.right = r.left;
  576. drawRect.top = clientRect.top;
  577. drawRect.bottom = clientRect.bottom;
  578. FillRect(p.hdc, &drawRect, br);
  579. // right black box
  580. drawRect.left = r.right;
  581. drawRect.right = clientRect.right;
  582. drawRect.top = clientRect.top;
  583. drawRect.bottom = clientRect.bottom;
  584. FillRect(p.hdc, &drawRect, br);
  585. // top black box
  586. drawRect.left = clientRect.left;
  587. drawRect.right = clientRect.right;
  588. drawRect.top = clientRect.top;
  589. drawRect.bottom = r.top;
  590. FillRect(p.hdc, &drawRect, br);
  591. // bottom black box
  592. drawRect.left = clientRect.left;
  593. drawRect.right = clientRect.right;
  594. drawRect.top = r.bottom;
  595. drawRect.bottom = clientRect.bottom;
  596. FillRect(p.hdc, &drawRect, br);
  597. LOGBRUSH lb = {BS_SOLID, (COLORREF)overlay_color, };
  598. br = CreateBrushIndirect(&lb);
  599. FillRect(p.hdc, &r, br);
  600. DeleteObject(br);
  601. }
  602. SubsItem *cst = curSubtitle;
  603. if (cst)
  604. {
  605. int m_lastsubxp = cst->xPos;
  606. int m_lastsubyp = cst->yPos;
  607. HDC out = p.hdc;
  608. HGDIOBJ oldobj = SelectObject(out, subFont);
  609. SetBkMode(out, TRANSPARENT);
  610. int centerflags = 0;
  611. if (m_lastsubxp < 127) centerflags |= DT_LEFT;
  612. else if (m_lastsubxp > 127) centerflags |= DT_RIGHT;
  613. else centerflags |= DT_CENTER;
  614. if (m_lastsubyp < 127) centerflags |= DT_TOP;
  615. else if (m_lastsubyp > 127) centerflags |= DT_BOTTOM;
  616. // draw outline
  617. SetTextColor(out, RGB(0, 0, 0));
  618. for (int y = -1; y < 2; y++)
  619. for (int x = -1; x < 2; x++)
  620. {
  621. if (!y && !x) continue;
  622. RECT r2 = {subRect.left + x, subRect.top + y, subRect.right + x, subRect.bottom + y};
  623. DrawTextA(out, cst->text, -1, &r2, centerflags | DT_NOCLIP | DT_NOPREFIX);
  624. }
  625. // draw text
  626. SetTextColor(out, RGB(cst->colorRed, cst->colorGreen, cst->colorBlue));
  627. DrawTextA(out, cst->text, -1, &subRect, centerflags | DT_NOCLIP | DT_NOPREFIX);
  628. SelectObject(out, oldobj);
  629. }
  630. EndPaint(hwnd, &p);
  631. return 1;
  632. }
  633. bool OverlayVideoOutput::LockSurface(DDSURFACEDESC *dd)
  634. {
  635. for (;;Sleep(0))
  636. {
  637. HRESULT hr = lpBackBuffer->Lock(0, dd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
  638. if (dd->lpSurface)
  639. break;
  640. if (hr == DDERR_SURFACELOST)
  641. {
  642. lpddsPrimary->Restore();
  643. lpBackBuffer->Restore();
  644. hr = lpddsOverlay->Lock(0, dd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
  645. if (hr == DDERR_SURFACELOST)
  646. return false;
  647. }
  648. else if (hr != DDERR_WASSTILLDRAWING)
  649. return false;
  650. }
  651. return true;
  652. }
  653. void OverlayVideoOutput::displayFrame(const char *buf, int size, int time)
  654. {
  655. DDSURFACEDESC dd = {sizeof(dd), };
  656. //CT> vsync wait not used anymore
  657. //if (config_video_vsync) lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);
  658. if (!LockSurface(&dd))
  659. {
  660. needchange = 1;
  661. return ;
  662. }
  663. if (type == VIDEO_MAKETYPE('Y', 'V', '1', '2'))
  664. {
  665. YV12_PLANES *planes = (YV12_PLANES *)buf;
  666. DoGamma(planes, height);
  667. if (uyvy_output)
  668. YV12_to_UYVY((unsigned char*)dd.lpSurface, planes, dd.lPitch, width, height, flip);
  669. else if (yuy2_output)
  670. YV12_to_YUY2((unsigned char*)dd.lpSurface, planes, dd.lPitch, width, height, flip);
  671. else
  672. YV12_to_YV12((unsigned char*)dd.lpSurface, planes, dd.lPitch, width, height, flip);
  673. }
  674. else if (type == VIDEO_MAKETYPE('Y', 'U', 'Y', '2'))
  675. {
  676. if (yuy2_output)
  677. YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
  678. else if (uyvy_output)
  679. YUY2_to_UYVY((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
  680. else
  681. YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip); // is this right?
  682. }
  683. else if (type == VIDEO_MAKETYPE('U', 'Y', 'V', 'Y'))
  684. {
  685. if (yuy2_output)
  686. YUY2_to_UYVY((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
  687. else if (uyvy_output) // TODO check this is correct i.e. dup YUY2_to_YUY2(..) calls
  688. YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip);
  689. else
  690. YUY2_to_YUY2((unsigned char*)dd.lpSurface, buf, dd.lPitch, width, height, flip); // is this right?
  691. }
  692. lpBackBuffer->Unlock(&dd);
  693. lpddsOverlay->Flip(lpBackBuffer, DDFLIP_WAIT);
  694. }
  695. void OverlayVideoOutput::drawSubtitle(SubsItem *item)
  696. {
  697. curSubtitle = item;
  698. RECT oldrect = subRect;
  699. GetClientRect(parent, &subRect);
  700. if (item)
  701. {
  702. RECT oldwinRect = winRect;
  703. GetClientRect(parent, &winRect);
  704. if (!subFont || ((winRect.bottom - winRect.top) != (oldwinRect.bottom - oldwinRect.top)) || m_fontsize != item->fontSize)
  705. {
  706. if (subFont)
  707. DeleteObject(subFont);
  708. m_fontsize = item->fontSize;
  709. subFont = CreateFontA(14 + item->fontSize + 18 * (winRect.bottom - winRect.top) / 768, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
  710. }
  711. HDC out = GetDC(parent);
  712. SelectObject(out, subFont);
  713. SIZE s;
  714. GetTextExtentPoint32A(out, item->text, lstrlenA(item->text), &s);
  715. {
  716. // calcul for multiline text
  717. const char *p = item->text;
  718. int n = 0;
  719. while (*p != 0) if (*p++ == '\n') n++;
  720. if (n) s.cy *= (n + 1);
  721. }
  722. if (item->xPos > 127) // towards the right
  723. subRect.right -= ((subRect.right - subRect.left) * (255 - item->xPos)) / 256;
  724. else if (item->xPos < 127)
  725. subRect.left += ((subRect.right - subRect.left) * item->xPos) / 256;
  726. subRect.top += ((subRect.bottom - s.cy - subRect.top) * item->yPos) / 255;
  727. subRect.bottom = subRect.top + s.cy;
  728. ReleaseDC(parent, out);
  729. }
  730. //just redraw the correct portion
  731. InvalidateRect(parent, &oldrect, TRUE);
  732. InvalidateRect(parent, &subRect, TRUE);
  733. }
  734. void OverlayVideoOutput::resetSubtitle()
  735. {
  736. curSubtitle = NULL;
  737. subRect.top = 65536;
  738. }