vid_d3d.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. #include "vid_d3d.h"
  2. #include "vid_subs.h"
  3. #include "../nu/AutoWide.h"
  4. #include "videooutput.h"
  5. #include "../nsutil/image.h"
  6. #include <d3d9.h>
  7. #include "WinampAttributes.h"
  8. #include "IVideoD3DOSD.h"
  9. #include <stdint.h>
  10. struct YV12_PLANES;
  11. typedef HRESULT (WINAPI *DIRECT3DCREATE9EX)(UINT SDKVersion, IDirect3D9Ex **);
  12. typedef IDirect3D9 *(WINAPI *DIRECT3DCREATE9)(UINT SDKVersion);
  13. static DIRECT3DCREATE9EX creatorex=0;
  14. static DIRECT3DCREATE9 creator=0;
  15. static HMODULE d3d_lib = 0;
  16. static bool tried=false;
  17. static DWORD winver;
  18. extern IVideoOSD *posd;
  19. static bool CreateDirect3D(IDirect3D9 **d3d, IDirect3D9Ex **d3dEx)
  20. {
  21. if (!d3d_lib && !creator)
  22. {
  23. if (tried)
  24. return false;
  25. d3d_lib = LoadLibraryW(L"d3d9.dll");
  26. if (!d3d_lib)
  27. {
  28. tried=true;
  29. return false;
  30. }
  31. creatorex = (DIRECT3DCREATE9EX)GetProcAddress(d3d_lib, "Direct3DCreate9Ex");
  32. creator = (DIRECT3DCREATE9)GetProcAddress(d3d_lib, "Direct3DCreate9");
  33. if (!creatorex && !creator)
  34. {
  35. FreeLibrary(d3d_lib);
  36. tried=true;
  37. return false;
  38. }
  39. }
  40. if (creatorex)
  41. {
  42. if (SUCCEEDED(creatorex(D3D_SDK_VERSION, d3dEx)) && *d3dEx)
  43. {
  44. (*d3dEx)->QueryInterface(__uuidof(IDirect3D9), (void **)d3d);
  45. return true;
  46. }
  47. }
  48. if (creator)
  49. {
  50. *d3d = creator(D3D_SDK_VERSION);
  51. *d3dEx=0;
  52. return !!d3d;
  53. }
  54. return false;
  55. }
  56. static void BuildPresentationParameters(D3DPRESENT_PARAMETERS &presentation_parameters, HWND hwnd, D3DSWAPEFFECT swap_effect)
  57. {
  58. memset(&presentation_parameters, 0, sizeof(presentation_parameters));
  59. presentation_parameters.BackBufferWidth = 0;
  60. presentation_parameters.BackBufferHeight = 0;
  61. presentation_parameters.BackBufferFormat = D3DFMT_UNKNOWN;
  62. presentation_parameters.BackBufferCount = 1;
  63. presentation_parameters.MultiSampleType = D3DMULTISAMPLE_NONE;
  64. presentation_parameters.MultiSampleQuality = 0;
  65. presentation_parameters.SwapEffect = swap_effect;
  66. presentation_parameters.hDeviceWindow = hwnd;
  67. presentation_parameters.Windowed = TRUE;
  68. presentation_parameters.EnableAutoDepthStencil = FALSE;
  69. presentation_parameters.Flags = /*D3DPRESENTFLAG_LOCKABLE_BACKBUFFER |*/ D3DPRESENTFLAG_VIDEO;
  70. presentation_parameters.FullScreen_RefreshRateInHz = 0;
  71. presentation_parameters.PresentationInterval = (!config_video_vsync2 ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE);
  72. }
  73. static UINT FindMyMonitor(IDirect3D9 *d3d, HWND hwnd)
  74. {
  75. HMONITOR monitor=MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
  76. if (monitor)
  77. {
  78. UINT num_adapters = d3d->GetAdapterCount();
  79. for (UINT i=0;i!=num_adapters;i++)
  80. {
  81. if (d3d->GetAdapterMonitor(i) == monitor)
  82. return i;
  83. }
  84. }
  85. return D3DADAPTER_DEFAULT;
  86. }
  87. D3DDEVTYPE Direct3DVideoOutput::GetDeviceType(IDirect3D9 *d3d, UINT display_adapter)
  88. {
  89. D3DCAPS9 caps;
  90. D3DDEVTYPE device_type = D3DDEVTYPE_HAL;
  91. for(;;)
  92. {
  93. HRESULT hr = d3d->GetDeviceCaps(display_adapter, device_type, &caps);
  94. if (hr == S_OK)
  95. {
  96. if ((D3DPTFILTERCAPS_MAGFLINEAR & caps.StretchRectFilterCaps) && (D3DPTFILTERCAPS_MINFLINEAR & caps.StretchRectFilterCaps))
  97. stretch_filter = D3DTEXF_LINEAR;
  98. else if ((D3DPTFILTERCAPS_MAGFPOINT & caps.StretchRectFilterCaps) && (D3DPTFILTERCAPS_MINFPOINT & caps.StretchRectFilterCaps))
  99. stretch_filter = D3DTEXF_POINT;
  100. else
  101. stretch_filter = D3DTEXF_NONE;
  102. return device_type;
  103. }
  104. if (device_type == D3DDEVTYPE_HAL)
  105. device_type = D3DDEVTYPE_REF;
  106. else
  107. break;
  108. }
  109. return (D3DDEVTYPE)0;
  110. }
  111. static D3DSWAPEFFECT GetSwapEffect(IDirect3D9 *d3d, UINT adapter, D3DDEVTYPE device_type, bool ex)
  112. {
  113. if (ex)
  114. {
  115. D3DCAPS9 caps;
  116. d3d->GetDeviceCaps(adapter, device_type, &caps);
  117. if (caps.Caps & D3DCAPS_OVERLAY)
  118. {
  119. return D3DSWAPEFFECT_OVERLAY;
  120. }
  121. else
  122. {
  123. return D3DSWAPEFFECT_FLIPEX;// (D3DSWAPEFFECT)5;
  124. }
  125. }
  126. else
  127. {
  128. return D3DSWAPEFFECT_FLIP;
  129. }
  130. }
  131. Direct3DVideoOutput::Direct3DVideoOutput(HWND parent, VideoAspectAdjuster *_adjuster)
  132. {
  133. CreateDirect3D(&d3d, &d3dEx);
  134. device = 0;
  135. deviceEx = 0;
  136. surface = 0;
  137. width=0;
  138. height=0;
  139. GetWindowRect(parent, &last_rect);
  140. surface_type = D3DFMT_UNKNOWN;
  141. display_adapter = 0;
  142. subtitle_font = 0;
  143. current_subtitle = 0;
  144. need_change = 0;
  145. adjuster = _adjuster;
  146. hwnd = parent;
  147. opened=false;
  148. valid_surface=false;
  149. logo_surface = 0;
  150. input_type = 0;
  151. flip = 0;
  152. m_palette = 0;
  153. if (d3dEx)
  154. {
  155. display_adapter = FindMyMonitor(d3d, parent);
  156. D3DDEVTYPE device_type = GetDeviceType(d3d, display_adapter);
  157. swap_effect = GetSwapEffect(d3d, display_adapter, device_type, true);
  158. D3DPRESENT_PARAMETERS presentation_parameters;
  159. BuildPresentationParameters(presentation_parameters, parent, swap_effect);
  160. HRESULT hr = d3dEx->CreateDeviceEx(display_adapter, D3DDEVTYPE_HAL, parent,
  161. D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
  162. &presentation_parameters, 0,
  163. &deviceEx);
  164. if (FAILED(hr))
  165. { // try again with mixed processing
  166. hr = d3dEx->CreateDeviceEx(display_adapter, D3DDEVTYPE_HAL, parent,
  167. D3DCREATE_MIXED_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
  168. &presentation_parameters, 0,
  169. &deviceEx);
  170. if (FAILED(hr))
  171. { // and finally software
  172. hr = d3dEx->CreateDeviceEx(display_adapter, D3DDEVTYPE_HAL, parent,
  173. D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
  174. &presentation_parameters, 0,
  175. &deviceEx);
  176. }
  177. }
  178. if (SUCCEEDED(hr))
  179. deviceEx->QueryInterface(__uuidof(IDirect3DDevice9), (void **)&device);
  180. }
  181. if (!deviceEx)
  182. {
  183. display_adapter = FindMyMonitor(d3d, parent);
  184. D3DDEVTYPE device_type = GetDeviceType(d3d, display_adapter);
  185. swap_effect = GetSwapEffect(d3d, display_adapter, device_type, false);
  186. if (device_type)
  187. {
  188. D3DPRESENT_PARAMETERS presentation_parameters;
  189. BuildPresentationParameters(presentation_parameters, parent, swap_effect);
  190. HRESULT hr = d3d->CreateDevice(display_adapter, device_type, parent,
  191. D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
  192. &presentation_parameters,
  193. &device);
  194. if (FAILED(hr))
  195. { // try again with mixed processing
  196. hr = d3d->CreateDevice(display_adapter, device_type, parent,
  197. D3DCREATE_MIXED_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
  198. &presentation_parameters,
  199. &device);
  200. if (FAILED(hr))
  201. { // and finally software
  202. /*hr = */d3d->CreateDevice(display_adapter, device_type, parent,
  203. D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED|D3DCREATE_NOWINDOWCHANGES,
  204. &presentation_parameters,
  205. &device);
  206. }
  207. }
  208. }
  209. }
  210. if (device)
  211. {
  212. // TODO: retrieve dimensions from VideoOutput
  213. device->CreateOffscreenPlainSurface(128, 128, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &logo_surface, 0);
  214. ((IVideoD3DOSD *)posd)->CreateOSD(device);
  215. }
  216. }
  217. static D3DFORMAT GetColorFormat(unsigned int type)
  218. {
  219. switch(type)
  220. {
  221. case MAKEFOURCC('Y', 'V', '1', '2'):
  222. return (D3DFORMAT)type;
  223. case MAKEFOURCC('Y', 'U', 'Y', '2'):
  224. return D3DFMT_YUY2;
  225. case MAKEFOURCC('U', 'Y', 'V', 'Y'):
  226. return D3DFMT_UYVY;
  227. case MAKEFOURCC('R', 'G', 'B', '8'):
  228. return D3DFMT_P8;
  229. case MAKEFOURCC('R', 'G', '3', '2'):
  230. return D3DFMT_X8R8G8B8;
  231. case MAKEFOURCC('R', 'G', '2', '4'):
  232. return D3DFMT_R8G8B8;
  233. case MAKEFOURCC('R', '5', '5', '5'):
  234. return D3DFMT_X1R5G5B5;
  235. case MAKEFOURCC('R', '5', '6', '5'):
  236. return D3DFMT_R5G6B5;
  237. default:
  238. return (D3DFORMAT)D3DFMT_UNKNOWN;
  239. }
  240. }
  241. static bool SubstituteSurfaceType(D3DFORMAT surface_format, D3DFORMAT &substitute_format, int n)
  242. {
  243. if (surface_format == D3DFMT_R8G8B8)
  244. {
  245. switch(n)
  246. {
  247. case 0:
  248. substitute_format = D3DFMT_X8R8G8B8;
  249. return true;
  250. }
  251. }
  252. else if (surface_format == (D3DFORMAT)MAKEFOURCC('Y', 'V', '1', '2'))
  253. {
  254. switch(n)
  255. {
  256. case 0:
  257. substitute_format = D3DFMT_YUY2;
  258. return true;
  259. case 1:
  260. substitute_format = D3DFMT_UYVY;
  261. return true;
  262. case 2:
  263. substitute_format = D3DFMT_X8R8G8B8;
  264. return true;
  265. }
  266. }
  267. return false;
  268. }
  269. static void PreferredSurfaceType(D3DFORMAT &surface_format)
  270. {
  271. if (surface_format == D3DFMT_P8)
  272. {
  273. surface_format = D3DFMT_X8R8G8B8;
  274. }
  275. }
  276. void Direct3DVideoOutput::setVFlip(int on)
  277. {
  278. flip = on;
  279. if (config_video_fliprgb)
  280. flip = !flip;
  281. }
  282. int Direct3DVideoOutput::OpenVideo(int w, int h, unsigned int type, int flipit, double aspectratio)
  283. {
  284. if (!device)
  285. return 0;
  286. D3DFORMAT new_surface_type = GetColorFormat(type);
  287. if (new_surface_type == D3DFMT_UNKNOWN) // not supported
  288. return 0;
  289. PreferredSurfaceType(new_surface_type);
  290. input_type = type;
  291. // see what was set for the flip flag
  292. // as nsv streams are generally flipped
  293. // so we'll need to invert the handling
  294. flip = flipit;
  295. if (config_video_fliprgb)
  296. flip = !flip;
  297. // see if we can re-use our old surface
  298. if (!surface || surface_type != new_surface_type || w != width || h != height)
  299. {
  300. if (surface)
  301. {
  302. surface->Release();
  303. surface=0;
  304. }
  305. HRESULT hr;
  306. D3DFORMAT try_surface_type = new_surface_type;
  307. int n=0;
  308. do
  309. {
  310. hr = device->CreateOffscreenPlainSurface(w, h, try_surface_type, D3DPOOL_DEFAULT, &surface, 0);
  311. } while (hr != S_OK && SubstituteSurfaceType(new_surface_type, try_surface_type, n++));
  312. surface_type = try_surface_type;
  313. if (hr != S_OK)
  314. return 0;
  315. width = w;
  316. height =h;
  317. }
  318. valid_surface=false;
  319. opened=true;
  320. return 1;
  321. }
  322. void Direct3DVideoOutput::OnWindowSize()
  323. {
  324. if (device)
  325. {
  326. RECT wnd_rect;
  327. GetWindowRect(hwnd, &wnd_rect);
  328. if (need_change || !EqualRect(&wnd_rect, &last_rect))
  329. {
  330. if ( need_change || (last_rect.right - last_rect.left) != (wnd_rect.right - wnd_rect.left)
  331. || (last_rect.bottom - last_rect.top) != (wnd_rect.bottom - wnd_rect.top))
  332. {
  333. // TODO: check adapter
  334. D3DPRESENT_PARAMETERS presentation_parameters;
  335. BuildPresentationParameters(presentation_parameters, hwnd, swap_effect);
  336. //if (surface)
  337. // surface->Release();
  338. //surface=0;
  339. if (subtitle_font)
  340. subtitle_font->Release(); // I hate to do this but we might need a new font size, and it works around a bug
  341. subtitle_font = 0;
  342. if (((IVideoD3DOSD *)posd)->isOSDInited())
  343. {
  344. ((IVideoD3DOSD *)posd)->LostOSD();
  345. }
  346. HRESULT hr = device->Reset(&presentation_parameters);
  347. if (FAILED(hr))
  348. {
  349. if (surface)
  350. surface->Release();
  351. surface=0;
  352. /*hr = */device->Reset(&presentation_parameters);
  353. /*hr = */device->CreateOffscreenPlainSurface(width, height, surface_type, D3DPOOL_DEFAULT, &surface, 0);
  354. }
  355. if (((IVideoD3DOSD *)posd)->isOSDInited())
  356. {
  357. ((IVideoD3DOSD *)posd)->ResetOSD(device);
  358. }
  359. drawSubtitle(current_subtitle);
  360. last_rect = wnd_rect;
  361. hr = device->BeginScene();
  362. if (SUCCEEDED(hr))
  363. DoRender();
  364. }
  365. else
  366. {
  367. // TODO: check adapter
  368. }
  369. last_rect = wnd_rect;
  370. }
  371. }
  372. }
  373. HRESULT Direct3DVideoOutput::DoRender()
  374. {
  375. RECT r;
  376. r = last_rect;
  377. r.right -= r.left;
  378. r.left = 0;
  379. r.bottom -= r.top;
  380. r.top = 0;
  381. //GetClientRect(hwnd, &r);
  382. HRESULT hr ;
  383. IDirect3DSurface9 *back_buffer = 0;
  384. hr = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer);
  385. if (FAILED(hr))
  386. {
  387. need_change=1;
  388. device->EndScene();
  389. return hr;
  390. }
  391. RECT full_rect = r;
  392. adjuster->adjustAspect(r);
  393. if (opened && valid_surface)
  394. {
  395. RECT sides[4]={
  396. {0, 0, r.left, full_rect.bottom}, // left side
  397. {r.right, 0, full_rect.right, full_rect.bottom}, // right side
  398. {0, 0, full_rect.right, r.top}, // top
  399. {0, r.bottom, full_rect.right, full_rect.bottom} // bottom
  400. };
  401. for (int i=0;i<4;i++)
  402. hr=device->ColorFill(back_buffer, &sides[i], D3DCOLOR_XRGB(0, 0, 0));
  403. hr = device->StretchRect(surface, NULL, back_buffer, &r, stretch_filter);
  404. }
  405. else
  406. {
  407. hr=device->ColorFill(back_buffer, 0, D3DCOLOR_XRGB(0, 0, 0));
  408. HDC logo_dc=0;
  409. HRESULT hr = logo_surface->GetDC(&logo_dc);
  410. if (hr == S_OK)
  411. { // draw logo
  412. RECT r={0,0,128,128};
  413. adjuster->DrawLogo(logo_dc, &r);
  414. logo_surface->ReleaseDC(logo_dc);
  415. POINT logo_pt = {full_rect.right/2 - 64,full_rect.bottom/2 - 64};
  416. device->UpdateSurface(logo_surface, 0, back_buffer, &logo_pt);
  417. }
  418. }
  419. back_buffer->Release();
  420. if (current_subtitle && subtitle_font)
  421. {
  422. DWORD oldValue;
  423. device->GetRenderState(D3DRS_ALPHABLENDENABLE, &oldValue);
  424. device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  425. RECT subRect, origRect;
  426. GetClientRect(hwnd, &subRect);
  427. origRect = subRect;
  428. D3DCOLOR text_color = D3DCOLOR_XRGB(current_subtitle->colorRed, current_subtitle->colorGreen, current_subtitle->colorBlue);
  429. AutoWide wide_text(current_subtitle->text);
  430. // calculate where to draw
  431. // TODO: move to drawSubtitle
  432. subtitle_font->DrawTextW(NULL, wide_text, -1, &subRect, DT_TOP | DT_WORDBREAK | DT_NOCLIP | DT_CENTER | DT_CALCRECT, text_color);
  433. int height_delta = (origRect.bottom - origRect.top) - (subRect.bottom - subRect.top);
  434. subRect.top += height_delta;
  435. subRect.bottom += height_delta;
  436. // draw
  437. hr = subtitle_font->DrawTextW(NULL, wide_text, -1, &subRect, DT_TOP | DT_WORDBREAK | DT_NOCLIP | DT_CENTER, text_color);
  438. device->SetRenderState(D3DRS_ALPHABLENDENABLE, oldValue);
  439. }
  440. if (posd && ((IVideoD3DOSD *)posd)->Showing() && ((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
  441. {
  442. ((IVideoD3DOSD *)posd)->DrawOSD(device);
  443. }
  444. hr = device->EndScene();
  445. if (FAILED(hr))
  446. {
  447. need_change = 1;
  448. return hr;
  449. }
  450. if (deviceEx)
  451. hr = deviceEx->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_DONOTWAIT);
  452. else
  453. hr = device->Present(NULL, NULL, NULL, NULL);
  454. if (hr == D3DERR_DEVICELOST)
  455. need_change = 1;
  456. return hr;
  457. }
  458. void YV12_to_UYVY(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip);
  459. void YV12_to_YV12(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip);
  460. void YV12_to_YUY2(unsigned char *output, const YV12_PLANES *planes, int pitch, int width, int height, int flip);
  461. void YUY2_to_YUY2(unsigned char *output, const char *buf, int pitch, int width, int height, int flip);
  462. void Direct3DVideoOutput::displayFrame(const char *buf, int size, int time)
  463. {
  464. if (need_change || !surface)
  465. return;
  466. RECT r;
  467. GetClientRect(hwnd, &r);
  468. HRESULT hr = device->BeginScene();
  469. if (FAILED(hr))
  470. {
  471. need_change=1;
  472. return;
  473. }
  474. D3DLOCKED_RECT locked_surface;
  475. hr = surface->LockRect(&locked_surface, NULL, D3DLOCK_DISCARD);
  476. if (SUCCEEDED(hr))
  477. {
  478. if (input_type == MAKEFOURCC('Y','V','1','2'))
  479. {
  480. const YV12_PLANES *planes = (const YV12_PLANES *)buf;
  481. switch((DWORD)surface_type)
  482. {
  483. case MAKEFOURCC('Y','V','1','2'):
  484. YV12_to_YV12((unsigned char *)locked_surface.pBits, planes, locked_surface.Pitch, width, height, flip);
  485. break;
  486. case MAKEFOURCC('Y','U','Y','2'):
  487. YV12_to_YUY2((unsigned char *)locked_surface.pBits, planes, locked_surface.Pitch, width, height, flip);
  488. break;
  489. case MAKEFOURCC('U','Y','V','Y'):
  490. YV12_to_UYVY((unsigned char *)locked_surface.pBits, planes, locked_surface.Pitch, width, height, flip);
  491. break;
  492. case D3DFMT_X8R8G8B8:
  493. {
  494. const uint8_t *plane_bufs[3] = { planes->y.baseAddr, planes->v.baseAddr, planes->u.baseAddr};
  495. const size_t plane_strides[3] = { (size_t)planes->y.rowBytes, (size_t)planes->v.rowBytes, (size_t)planes->u.rowBytes };
  496. if (flip)
  497. nsutil_image_Convert_YUV420_RGB32((RGB32 *)((int8_t *)locked_surface.pBits + locked_surface.Pitch*(height-1)), -locked_surface.Pitch, width, height, plane_bufs, plane_strides);
  498. else
  499. nsutil_image_Convert_YUV420_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, width, height, plane_bufs, plane_strides);
  500. }
  501. break;
  502. }
  503. }
  504. else if (surface_type == D3DFMT_YUY2) // YUY2
  505. {
  506. YUY2_to_YUY2((unsigned char *)locked_surface.pBits, buf, locked_surface.Pitch, width, height, flip);
  507. }
  508. else if (surface_type == D3DFMT_UYVY) // YUY2
  509. {
  510. YUY2_to_YUY2((unsigned char *)locked_surface.pBits, buf, locked_surface.Pitch, width, height, flip);
  511. }
  512. else if (surface_type == D3DFMT_P8) // 8bit with palette
  513. {
  514. if (flip)
  515. nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height);
  516. else
  517. nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height);
  518. }
  519. else if (surface_type == D3DFMT_X8R8G8B8) // RGB32
  520. {
  521. if (input_type == MAKEFOURCC('R','G','3','2'))
  522. {
  523. if (flip)
  524. nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*4, width*4, height);
  525. else
  526. nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*4, width*4, height);
  527. }
  528. else if (input_type == MAKEFOURCC('R','G','2','4'))
  529. {
  530. if (flip)
  531. nsutil_image_ConvertFlipped_RGB24_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*3, width, height);
  532. else
  533. nsutil_image_Convert_RGB24_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*3, width, height);
  534. }
  535. else if (input_type == MAKEFOURCC('R','G','B','8') && m_palette)
  536. {
  537. if (flip)
  538. nsutil_image_PaletteFlipped_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height, (RGB32 *)m_palette);
  539. else
  540. nsutil_image_Palette_RGB32((RGB32 *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width, width, height, (RGB32 *)m_palette);
  541. }
  542. }
  543. else if (surface_type == D3DFMT_R8G8B8) // RGB24
  544. {
  545. if (flip || locked_surface.Pitch != width*3)
  546. {
  547. char *start = (char *)locked_surface.pBits;
  548. if (flip)
  549. start += locked_surface.Pitch * (height-1);
  550. ptrdiff_t pitch = flip?-locked_surface.Pitch:locked_surface.Pitch;
  551. for (int i=0;i<height;i++)
  552. {
  553. char *line = start + pitch * i;
  554. memcpy(line, buf + width*i*3, width*3);
  555. }
  556. }
  557. else
  558. {
  559. memcpy(locked_surface.pBits, buf, width*height*3);
  560. }
  561. }
  562. else if (surface_type == D3DFMT_X1R5G5B5)
  563. {
  564. if (flip)
  565. nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
  566. else
  567. nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
  568. }
  569. else if (surface_type == D3DFMT_R5G6B5)
  570. {
  571. if (flip)
  572. nsutil_image_CopyFlipped_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
  573. else
  574. nsutil_image_Copy_U8((uint8_t *)locked_surface.pBits, locked_surface.Pitch, (const uint8_t *)buf, width*2, width*2, height);
  575. }
  576. valid_surface = true;
  577. /*hr = */surface->UnlockRect();
  578. }
  579. DoRender();
  580. }
  581. void Direct3DVideoOutput::close()
  582. {
  583. opened=false;
  584. }
  585. int Direct3DVideoOutput::onPaint(HWND hwnd)
  586. {
  587. PAINTSTRUCT p;
  588. BeginPaint(hwnd, &p);
  589. if (swap_effect == D3DSWAPEFFECT_OVERLAY)
  590. {
  591. deviceEx->PresentEx(0, 0, 0, 0, D3DPRESENT_UPDATEOVERLAYONLY);
  592. }
  593. else
  594. {
  595. RECT r;
  596. GetClientRect(hwnd, &r);
  597. if (surface && !need_change)
  598. {
  599. HRESULT hr = device->BeginScene();
  600. if (SUCCEEDED(hr))
  601. DoRender();
  602. else
  603. need_change=1;
  604. }
  605. }
  606. EndPaint(hwnd, &p);
  607. return 1;
  608. }
  609. void Direct3DVideoOutput::Refresh()
  610. {
  611. /* TODO: sanity check but do this
  612. HRESULT hr = device->BeginScene();
  613. IDirect3DSurface9 *back_buffer = 0;
  614. hr = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer);
  615. adjuster->adjustAspect(r);
  616. hr = device->StretchRect(surface, NULL, back_buffer, &r, stretch_filter);
  617. back_buffer->Release();
  618. hr = device->EndScene();
  619. hr = device->Present(NULL, NULL, NULL, NULL);
  620. */
  621. InvalidateRect(hwnd, NULL, TRUE);
  622. }
  623. void Direct3DVideoOutput::timerCallback()
  624. {
  625. }
  626. void Direct3DVideoOutput::drawSubtitle(SubsItem *item)
  627. {
  628. current_subtitle = item;
  629. if (current_subtitle)
  630. {
  631. if (!subtitle_font)
  632. {
  633. int font_size = 14 + item->fontSize + MulDiv(18, (last_rect.bottom - last_rect.top), 768);
  634. pCreateFontW(device, font_size, 0, 400,
  635. 1,
  636. 0,
  637. DEFAULT_CHARSET,
  638. OUT_DEFAULT_PRECIS,
  639. ANTIALIASED_QUALITY,//DEFAULT_QUALITY,
  640. DEFAULT_PITCH,
  641. L"Arial",
  642. &subtitle_font);
  643. }
  644. if (subtitle_font)
  645. {
  646. // TODO: make an AutoWideDup and use during rendering also, saves some mallocs
  647. AutoWide wide_text(item->text, CP_UTF8);
  648. if (wide_text)
  649. subtitle_font->PreloadTextW(wide_text, lstrlenW(wide_text));
  650. // TODO: DT_CALCRECT
  651. }
  652. }
  653. }
  654. void Direct3DVideoOutput::resetSubtitle()
  655. {
  656. current_subtitle = 0;
  657. }
  658. void Direct3DVideoOutput::setPalette(RGBQUAD *pal)
  659. {
  660. /* benski> can't get D3DFMT_P8 surfaces to use this during StretchRect, so I'll just forget about it
  661. for (int i=0;i<256;i++)
  662. {
  663. pal[i].rgbReserved = 0xFF;
  664. }
  665. HRESULT hr = device->SetPaletteEntries(0, (CONST PALETTEENTRY *)pal);
  666. hr = device->SetCurrentTexturePalette(0);
  667. hr = device->SetPaletteEntries(0, (CONST PALETTEENTRY *)pal);*/
  668. m_palette = pal;
  669. }