1
0

VideoOutput.cpp 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. #include <windowsx.h>
  2. #include "main.h"
  3. #include "VideoOutput.h"
  4. #include "VideoOutputChild.h"
  5. #include "vid_none.h"
  6. #include "vid_ddraw.h"
  7. #include "vid_overlay.h"
  8. #include "vid_d3d.h"
  9. #include <cassert>
  10. #include "directdraw.h"
  11. #include "video.h"
  12. #include "api.h"
  13. #include "WinampAttributes.h"
  14. #include "resource.h"
  15. #include "../nu/AutoWide.h"
  16. #include "stats.h"
  17. #include "IVideoD3DOSD.h"
  18. extern "C" int is_fullscreen_video;
  19. #define WM_VIDEO_UPDATE_STATUS_TEXT WM_USER+0x874
  20. #define WM_VIDEO_OPEN WM_USER+0x875
  21. #define WM_VIDEO_CLOSE WM_USER+0x876
  22. #define WM_VIDEO_RESIZE WM_USER+0x877
  23. #define WM_VIDEO_OSDCHANGE WM_USER+0x888
  24. #define WM_VIDEO_CREATE WM_USER+0x900
  25. int g_bitmap_id = IDB_VIDEOLOGO;
  26. int VideoOutput::class_refcnt = 0;
  27. wchar_t vidoutbuf_save[1024] = {0};
  28. static bool input_plugin_thread_safe = false;
  29. //#define USE_GDIPLUS_VIDEO_RENDERER
  30. IVideoOSD *posd = new IVideoD3DOSD;
  31. HRESULT(WINAPI *_DirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter) = 0;
  32. void OpenDirectDraw()
  33. {
  34. static int a = 0;
  35. if (!_DirectDrawCreate && !a)
  36. {
  37. a++;
  38. HINSTANCE h = LoadLibraryW(L"ddraw.dll");
  39. if (h)
  40. {
  41. *(void**)&_DirectDrawCreate = (void*)GetProcAddress(h, "DirectDrawCreate");
  42. }
  43. }
  44. }
  45. HMENU BuildPopupMenu()
  46. {
  47. HMENU menu = GetSubMenu(GetSubMenu(top_menu, 3), 13);
  48. {
  49. static int menuset = 0;
  50. if (!menuset)
  51. {
  52. InsertMenu(menu, (UINT)-1, MF_BYPOSITION | MF_SEPARATOR, 0, 0);
  53. InsertMenuA(menu, (UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)GetSubMenu(top_menu, 0), "Winamp");
  54. menuset = 1;
  55. }
  56. }
  57. updateTrackSubmenu();
  58. return menu;
  59. }
  60. void VideoOutput::mainthread_Create()
  61. {
  62. if (!video_created)
  63. {
  64. m_video_output = new Direct3DVideoOutput(video_hwnd, this);
  65. video_created=true;
  66. }
  67. }
  68. VideoOutput::VideoOutput(HWND parent_hwnd, int initxpos, int initypos)
  69. : m_logo(0),
  70. m_logo_w(0),
  71. m_logo_h(0),
  72. userVideo(false)
  73. {
  74. video_palette = 0;
  75. video_created = false;
  76. AutoLock autoLock(guard LOCKNAME("VideoOutput::VideoOutput"));
  77. WNDCLASSW wc = {0, };
  78. wc.style = CS_DBLCLKS;
  79. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  80. wc.lpfnWndProc = WndProc;
  81. wc.hInstance = GetModuleHandle(NULL);
  82. wc.lpszClassName = L"WinampVideoChild";
  83. wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  84. if (!class_refcnt) RegisterClassW(&wc);
  85. class_refcnt++;
  86. m_tracksel = NULL;
  87. fs_reparented_rgn = 0;
  88. fs_reparented = 0;
  89. m_ignore_change = false;
  90. fs_has_resized = false;
  91. m_opened = 0;
  92. last_fullscreen_exit_time = 0;
  93. curSubtitle = NULL;
  94. m_statusmsg = 0;
  95. m_bufferstate = -1;
  96. m_msgcallback = 0;
  97. m_msgcallback_tok = 0;
  98. video_hwnd = 0;
  99. aspect = 1.0;
  100. m_need_change = false;
  101. is_fs = 0;
  102. memset(&oldfsrect, 0, sizeof(oldfsrect));
  103. memset(&lastfsrect, 0, sizeof(lastfsrect));
  104. m_video_output = NULL;
  105. resetSubtitle();
  106. m_lastbufinvalid = NULL;
  107. CreateWindowExW(0, wc.lpszClassName, L"WinampVideoChildWindow",
  108. parent_hwnd ? WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS :
  109. (WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX)),
  110. 0, 0, 1, 1,
  111. parent_hwnd, NULL, wc.hInstance, (void*)this);
  112. posd->SetParent(video_hwnd);
  113. }
  114. VideoOutput::~VideoOutput()
  115. {
  116. AutoLock autoLock(guard LOCKNAME("VideoOutput::~VideoOutput"));
  117. free(m_statusmsg);
  118. posd->Hide();
  119. if (m_video_output) m_video_output->close();
  120. m_video_output = 0;
  121. DestroyWindow(video_hwnd);
  122. if (m_logo)
  123. DeleteObject(m_logo);
  124. m_logo = 0;
  125. if (posd)
  126. {
  127. delete posd;
  128. posd = NULL;
  129. }
  130. }
  131. void VideoOutput::LoadLogo()
  132. {
  133. static wchar_t logo_tmp[MAX_PATH];
  134. if(!logo_tmp[0]) StringCchPrintfW(logo_tmp,MAX_PATH,L"%s\\videologo.bmp",CONFIGDIR);
  135. if(PathFileExistsW(logo_tmp)) m_logo = (HBITMAP)LoadImageW(0,logo_tmp,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
  136. if(!m_logo) m_logo = (HBITMAP)LoadImage(hMainInstance, MAKEINTRESOURCE(g_bitmap_id), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  137. BITMAP bm;
  138. GetObject(m_logo, sizeof(BITMAP), &bm);
  139. m_logo_w = bm.bmWidth;
  140. m_logo_h = bm.bmHeight;
  141. if (m_logo_h < 0)
  142. m_logo_h = -m_logo_h;
  143. }
  144. void VideoOutput::UpdateText(const wchar_t *videoInfo)
  145. {
  146. {
  147. //AutoLock lock(textGuard);
  148. StringCchCopyW(vidoutbuf_save, 1023, (wchar_t*)videoInfo); // 1023 so that we can guarantee that this will be null terminated even in the middle of a strcpy
  149. }
  150. PostMessageW(hVideoWindow, WM_VIDEO_UPDATE_STATUS_TEXT, (WPARAM)vidoutbuf_save, 0);
  151. PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_VIDEOINFO, IPC_CB_MISC);
  152. }
  153. INT_PTR VideoOutput::extended(INT_PTR param1, INT_PTR param2, INT_PTR param3)
  154. {
  155. switch (param1) // nonlocking commands
  156. {
  157. case VIDUSER_GET_VIDEOHWND:
  158. return (INT_PTR)video_hwnd;
  159. case VIDUSER_SET_INFOSTRING:
  160. if (param2)
  161. UpdateText(AutoWide((const char *)param2));
  162. return 0;
  163. case VIDUSER_SET_INFOSTRINGW:
  164. if (param2)
  165. UpdateText((const wchar_t *)param2);
  166. return 0;
  167. }
  168. AutoLock autoLock(guard LOCKNAME("VideoOutput::extended"));
  169. switch (param1)
  170. {
  171. case VIDUSER_SET_PALETTE:
  172. {
  173. RGBQUAD *palette = (RGBQUAD *)param2;
  174. if (m_video_output)
  175. m_video_output->setPalette(palette);
  176. else
  177. video_palette = palette;
  178. return 0;
  179. }
  180. case VIDUSER_SET_VFLIP:
  181. {
  182. if (m_video_output)
  183. m_video_output->setVFlip(param2);
  184. return 0;
  185. }
  186. case VIDUSER_SET_TRACKSELINTERFACE:
  187. m_tracksel = (ITrackSelector *)param2;
  188. return 0;
  189. case VIDUSER_OPENVIDEORENDERER:
  190. {/*
  191. userVideo = true;
  192. m_video_output = (VideoRenderer *)param2;
  193. VideoOpenStruct *openStruct = (VideoOpenStruct *)param3;
  194. int x = openUser(openStruct->w, openStruct->h, openStruct->vflip, openStruct->aspectratio, openStruct->fmt);
  195. if (x)
  196. {
  197. m_video_output = 0;
  198. userVideo = false;
  199. return 0;
  200. }
  201. else*/
  202. return 1;
  203. }
  204. case VIDUSER_CLOSEVIDEORENDERER:
  205. close();
  206. userVideo = false;
  207. return 1;
  208. case VIDUSER_GETPOPUPMENU:
  209. return (INT_PTR)BuildPopupMenu();
  210. case VIDUSER_SET_THREAD_SAFE:
  211. input_plugin_thread_safe = !!param2;
  212. break;
  213. }
  214. return 0;
  215. }
  216. int VideoOutput::get_latency()
  217. {
  218. return config_video_vsync2 ? 15 : 0;
  219. }
  220. void VideoOutput::adjustAspect(RECT &rd)
  221. {
  222. AutoLock autoLock(guard LOCKNAME("VideoOutput::adjustAspect"));
  223. if (posd->Showing() /*&& config_video_osd*/)
  224. {
  225. rd.top += posd->GetBarHeight();
  226. rd.bottom -= posd->GetBarHeight();
  227. }
  228. if (config_video_aspectadj)
  229. {
  230. int outh = rd.bottom - rd.top;
  231. int outw = rd.right - rd.left;
  232. double outputaspect = aspect;
  233. if (config_video_useratio && config_video_ratio1 && config_video_ratio2)
  234. {
  235. RECT r;
  236. getViewport(&r, hVideoWindow, 1, NULL);
  237. int screenx = r.right - r.left;
  238. int screeny = r.bottom - r.top;
  239. if (screenx && screeny)
  240. {
  241. outputaspect *= config_video_ratio1 * screeny / ((double)screenx * (double)config_video_ratio2);
  242. }
  243. }
  244. int newh = (int)((outputaspect * height * outw) / (double)width);
  245. int neww = (int)((width * outh) / (height * outputaspect));
  246. if (outh > newh) // black bars on top and bottom
  247. {
  248. int d = outh - newh;
  249. rd.top += d / 2;
  250. rd.bottom -= d - d / 2;
  251. }
  252. else if (outw > neww) // black bars on left and right
  253. {
  254. int d = outw - neww;
  255. rd.left += d / 2;
  256. rd.right -= d - d / 2;
  257. }
  258. }
  259. }
  260. LRESULT CALLBACK VideoOutput::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  261. {
  262. if (uMsg == g_scrollMsg) // can't check against variables in case statements
  263. {
  264. wParam <<= 16;
  265. uMsg = WM_MOUSEWHEEL;
  266. }
  267. if (FALSE != IsDirectMouseWheelMessage(uMsg))
  268. {
  269. SendMessageW(hwnd, WM_MOUSEWHEEL, wParam, lParam);
  270. return TRUE;
  271. }
  272. switch (uMsg)
  273. {
  274. case WM_MOUSEWHEEL:
  275. return SendMessageW(hMainWindow, uMsg, wParam, lParam);
  276. case WM_CREATE:
  277. {
  278. VideoOutput *vid = (VideoOutput *)((CREATESTRUCT *)lParam)->lpCreateParams;
  279. vid->video_hwnd = hwnd;
  280. SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)vid);
  281. }
  282. return 0;
  283. default: /// pass it on to the other window procedure
  284. VideoOutput *_This = (VideoOutput*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
  285. if (_This)
  286. return _This->WindowProc(hwnd, uMsg, wParam, lParam);
  287. else
  288. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  289. }
  290. }
  291. void VideoOutput::notifyBufferState(int bufferstate) /* 0-255*/
  292. {
  293. m_bufferstate = bufferstate;
  294. if (bufferstate == -1 || bufferstate == 255 || (GetTickCount() - m_lastbufinvalid > 500)) // don't want to do this too often
  295. {
  296. AutoLock autoLock(guard LOCKNAME("VideoOutput::notifyBufferState"));
  297. if (!m_video_output || !m_video_output->onPaint(video_hwnd))
  298. InvalidateRect(video_hwnd, 0, TRUE);
  299. m_lastbufinvalid = GetTickCount();
  300. }
  301. }
  302. void VideoOutput::DrawLogo(HDC out, RECT *canvas_size)
  303. {
  304. int bufferState = m_bufferstate;
  305. if (m_logo && config_video_logo)
  306. {
  307. HDC dc = CreateCompatibleDC(NULL);
  308. SelectObject(dc, m_logo);
  309. int xp = (canvas_size->right - canvas_size->left - m_logo_w) / 2;
  310. int yp = (canvas_size->bottom - canvas_size->top - m_logo_h) / 2;
  311. BitBlt(out, xp, yp, m_logo_w, m_logo_h, dc, 0, 0, SRCCOPY);
  312. if (bufferState != -1)
  313. {
  314. if (bufferState < 16) bufferState = 16;
  315. HGDIOBJ oldobj1 = SelectObject(out, CreateSolidBrush(RGB(0, 0, 0)));
  316. HGDIOBJ oldobj2 = SelectObject(out, CreatePen(PS_SOLID, 0, RGB(0, 0, 0)));
  317. Rectangle(out, canvas_size->left, canvas_size->top, canvas_size->right, yp);
  318. if (m_statusmsg)
  319. Rectangle(out, canvas_size->left, yp + m_logo_h, canvas_size->right, canvas_size->bottom);
  320. else
  321. {
  322. Rectangle(out, canvas_size->left, yp + m_logo_h + 2 + 9, canvas_size->right, canvas_size->bottom);
  323. Rectangle(out, xp + ((bufferState *(m_logo_w + 2)) >> 8), yp + m_logo_h + 2, canvas_size->right, yp + 9 + m_logo_h + 2);
  324. }
  325. Rectangle(out, canvas_size->left, yp, xp - 1, yp + m_logo_h + 9 + 2);
  326. Rectangle(out, xp + m_logo_w + 1, yp, canvas_size->right, yp + m_logo_h + 2);
  327. DeleteObject(SelectObject(out, oldobj2));
  328. DeleteObject(SelectObject(out, oldobj1));
  329. }
  330. if (m_statusmsg)
  331. {
  332. RECT subr = {0, yp + m_logo_h + 2, canvas_size->right, canvas_size->bottom};
  333. SetTextColor(out, RGB(255, 255, 255));
  334. SetBkMode(out, TRANSPARENT);
  335. DrawTextA(out, m_statusmsg, -1, &subr, DT_TOP | DT_CENTER | DT_NOCLIP | DT_NOPREFIX);
  336. }
  337. else
  338. {
  339. yp += m_logo_h + 2;
  340. if (bufferState)
  341. {
  342. HGDIOBJ oldobj1 = SelectObject(out, CreateSolidBrush(RGB(128, 128, 128)));
  343. HGDIOBJ oldobj2 = SelectObject(out, CreatePen(PS_SOLID, 0, RGB(255, 255, 255)));
  344. Rectangle(out, xp - 1, yp, xp + ((bufferState *(m_logo_w + 2)) >> 8), yp + 9);
  345. DeleteObject(SelectObject(out, oldobj2));
  346. DeleteObject(SelectObject(out, oldobj1));
  347. }
  348. }
  349. DeleteDC(dc);
  350. }
  351. }
  352. void VideoOutput::PaintLogo(int bufferState)
  353. {
  354. // TODO: ask renderer to draw this shiz
  355. AutoLock autoLock(guard LOCKNAME("VideoOutput::PaintLogo"));
  356. PAINTSTRUCT p;
  357. BeginPaint(video_hwnd, &p);
  358. RECT r;
  359. GetClientRect(video_hwnd, &r);
  360. HDC out = p.hdc;
  361. HRGN hrgn = CreateRectRgnIndirect(&r);
  362. HBRUSH b = (HBRUSH)GetStockObject(BLACK_BRUSH);
  363. FillRgn(out, hrgn, b);
  364. DeleteObject(b);
  365. DeleteObject(hrgn);
  366. DrawLogo(out, &r);
  367. EndPaint(video_hwnd, &p);
  368. }
  369. // the big window procedure
  370. LRESULT VideoOutput::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  371. {
  372. // the follow messages are handled w/o a lock
  373. switch (uMsg)
  374. {
  375. case WM_USER + 0x1:
  376. m_need_change = true;
  377. break;
  378. case WM_USER + 0x2:
  379. m_ignore_change = !!lParam;
  380. break;
  381. case WM_ERASEBKGND:
  382. return 1;
  383. case WM_COMMAND:
  384. switch (LOWORD(wParam))
  385. {
  386. case ID_VIDEOWND_VIDEOOPTIONS:
  387. prefs_last_page = 24;
  388. prefs_dialog(1);
  389. break;
  390. case ID_VID_AUDIO0:
  391. case ID_VID_AUDIO1:
  392. case ID_VID_AUDIO2:
  393. case ID_VID_AUDIO3:
  394. case ID_VID_AUDIO4:
  395. case ID_VID_AUDIO5:
  396. case ID_VID_AUDIO6:
  397. case ID_VID_AUDIO7:
  398. case ID_VID_AUDIO8:
  399. case ID_VID_AUDIO9:
  400. case ID_VID_AUDIO10:
  401. case ID_VID_AUDIO11:
  402. case ID_VID_AUDIO12:
  403. case ID_VID_AUDIO13:
  404. case ID_VID_AUDIO14:
  405. case ID_VID_AUDIO15:
  406. {
  407. VideoOutput *out = (VideoOutput *)video_getIVideoOutput();
  408. if (!out)
  409. break;
  410. out->getTrackSelector()->setAudioTrack(LOWORD(wParam) - ID_VID_AUDIO0);
  411. break;
  412. }
  413. case ID_VID_VIDEO0:
  414. case ID_VID_VIDEO1:
  415. case ID_VID_VIDEO2:
  416. case ID_VID_VIDEO3:
  417. case ID_VID_VIDEO4:
  418. case ID_VID_VIDEO5:
  419. case ID_VID_VIDEO6:
  420. case ID_VID_VIDEO7:
  421. case ID_VID_VIDEO8:
  422. case ID_VID_VIDEO9:
  423. case ID_VID_VIDEO10:
  424. case ID_VID_VIDEO11:
  425. case ID_VID_VIDEO12:
  426. case ID_VID_VIDEO13:
  427. case ID_VID_VIDEO14:
  428. case ID_VID_VIDEO15:
  429. {
  430. VideoOutput *out = (VideoOutput *)video_getIVideoOutput();
  431. if (!out) break;
  432. out->getTrackSelector()->setVideoTrack(LOWORD(wParam) - ID_VID_VIDEO0);
  433. break;
  434. }
  435. }
  436. break;
  437. case WM_RBUTTONUP:
  438. if (!is_fs)
  439. {
  440. POINT p;
  441. GetCursorPos(&p);
  442. DoTrackPopup(BuildPopupMenu(), TPM_RIGHTBUTTON | TPM_LEFTBUTTON, p.x, p.y, hwnd);
  443. }
  444. break;
  445. case WM_LBUTTONDOWN: // putting this here prevents a deadlock, but allows a race condition over video drawing =(
  446. {
  447. int x = GET_X_LPARAM(lParam);
  448. int y = GET_Y_LPARAM(lParam);
  449. if (is_fs && config_video_osd)
  450. {
  451. if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
  452. {
  453. if (posd->MouseDown(x, y, wParam))
  454. videoToggleFullscreen();
  455. }
  456. }
  457. else
  458. {
  459. SetCapture(video_hwnd);
  460. clickx = x;
  461. clicky = y;
  462. SetFocus(video_hwnd);
  463. }
  464. }
  465. break;
  466. case WM_MOUSEMOVE:
  467. {
  468. int x = GET_X_LPARAM(lParam);
  469. int y = GET_Y_LPARAM(lParam);
  470. if (is_fs && config_video_osd)
  471. {
  472. if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
  473. {
  474. posd->MouseMove(x, y, wParam);
  475. }
  476. }
  477. else if (GetCapture() == video_hwnd && config_easymove)
  478. {
  479. POINT p = { x, y};
  480. ClientToScreen(hVideoWindow, &p);
  481. p.x -= clickx;
  482. p.y -= clicky;
  483. SendMessageW(hVideoWindow, WM_USER + 0x100, 1, (LPARAM)&p);
  484. }
  485. }
  486. break;
  487. case WM_LBUTTONUP:
  488. {
  489. int x = GET_X_LPARAM(lParam);
  490. int y = GET_Y_LPARAM(lParam);
  491. if (GetCapture() == video_hwnd)
  492. ReleaseCapture();
  493. if (is_fs && config_video_osd)
  494. {
  495. if (((IVideoD3DOSD *)posd)->isOSDReadyToDraw())
  496. if (posd->MouseUp(x, y, wParam))
  497. videoToggleFullscreen();
  498. }
  499. SetFocus(hVideoWindow);
  500. }
  501. break;
  502. }
  503. switch (uMsg)
  504. {
  505. case WM_VIDEO_OSDCHANGE:
  506. {
  507. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_VIDEO_OSDCHANGE"));
  508. if (m_video_output)
  509. {
  510. m_video_output->Refresh();
  511. m_video_output->timerCallback();
  512. }
  513. }
  514. break;
  515. case WM_SHOWWINDOW:
  516. {
  517. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SHOWWINDOW"));
  518. if (wParam == TRUE // being shown
  519. && !m_logo) // logo hasn't been loaded yet
  520. LoadLogo();
  521. }
  522. break;
  523. case WM_INITMENUPOPUP:
  524. {
  525. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_INITMENUPOPUP"));
  526. return SendMessageW(hMainWindow, uMsg, wParam, lParam); // for popup menus
  527. }
  528. case WM_WINDOWPOSCHANGED:
  529. case WM_SIZE:
  530. {
  531. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SIZE"));
  532. if (m_video_output)
  533. {
  534. m_video_output->OnWindowSize();
  535. if (is_fs)
  536. if ( ((IVideoD3DOSD *)posd)->isOSDInited() )
  537. ((IVideoD3DOSD *)posd)->UpdateOSD(hwnd, this);
  538. }
  539. }
  540. break;
  541. case WM_TIMER:
  542. case WM_WINDOWPOSCHANGING:
  543. case WM_MOVE:
  544. case WM_MOVING:
  545. {
  546. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_TIMER, etc"));
  547. if (m_video_output && !m_ignore_change)
  548. m_video_output->timerCallback();
  549. if (uMsg == WM_TIMER)
  550. return 0;
  551. }
  552. break;
  553. case WM_LBUTTONDBLCLK:
  554. {
  555. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_LBUTTONDBLCLK"));
  556. videoToggleFullscreen();
  557. }
  558. break;
  559. case WM_PAINT:
  560. {
  561. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_PAINT"));
  562. if (m_video_output && m_video_output->onPaint(hwnd))
  563. return 0;
  564. PaintLogo(m_bufferstate);
  565. }
  566. return 0;
  567. break;
  568. case WM_PRINTCLIENT:
  569. {
  570. //AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_PAINT"));
  571. //if (m_video_output && m_video_output->onPaint(hwnd))
  572. // return 0;
  573. RECT r;
  574. GetClientRect(video_hwnd, &r);
  575. DrawLogo((HDC)wParam, &r);
  576. }
  577. return 0;
  578. break;
  579. case WM_KEYDOWN:
  580. {
  581. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_KEYDOWN"));
  582. if (wParam == VK_ESCAPE && is_fs)
  583. {
  584. videoToggleFullscreen();
  585. //remove_fullscreen();
  586. return 1;
  587. }
  588. if (!is_fs)
  589. {
  590. if (wParam == '3' || LOWORD(wParam) == 192 /* ` */)
  591. {
  592. SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM50, 0); return 0;
  593. }
  594. if (wParam == '1')
  595. {
  596. SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM100, 0); return 0;
  597. }
  598. if (wParam == '2')
  599. {
  600. SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_ZOOM200, 0); return 0;
  601. }
  602. }
  603. if (wParam == ' ')
  604. {
  605. SendMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0); return 0;
  606. }
  607. if(wParam == 'F' && (GetAsyncKeyState(VK_SHIFT)&0x8000) && !(GetAsyncKeyState(VK_CONTROL)&0x8000))
  608. {
  609. SendMessageW(hwnd, WM_COMMAND, ID_VIDEOWND_VERTICALLYFLIP, 0); return 0;
  610. }
  611. }
  612. break;
  613. case WM_COMMAND:
  614. {
  615. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_COMMAND"));
  616. switch (LOWORD(wParam))
  617. {
  618. case ID_VIDEOWND_VERTICALLYFLIP:
  619. {
  620. int new_fliprgb = !config_video_fliprgb;//IsDlgButtonChecked(hwndDlg,IDC_PREFS_VIDEO_FLIPRGB)?1:0;
  621. config_video_fliprgb = 0;
  622. videoSetFlip(new_fliprgb);
  623. config_video_fliprgb = new_fliprgb;
  624. break;
  625. }
  626. case ID_VIDEOWND_ZOOMFULLSCREEN:
  627. videoGoFullscreen();
  628. break;
  629. case ID_VIDEOWND_ZOOM200:
  630. case ID_VIDEOWND_ZOOM100:
  631. case ID_VIDEOWND_ZOOM50:
  632. if (m_video_output)
  633. UpdateVideoSize(width, height, aspect, LOWORD(wParam));
  634. else
  635. UpdateVideoSize(320, 240, 1.0, LOWORD(wParam));
  636. break;
  637. default:
  638. SendMessageW(hMainWindow, WM_COMMAND, wParam, lParam);
  639. break;
  640. }
  641. }
  642. break;
  643. case WM_SETCURSOR:
  644. {
  645. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SETCURSOR"));
  646. if (is_fs)
  647. {
  648. SetCursor(posd->Showing() ? LoadCursor(NULL, IDC_ARROW) : NULL);
  649. return TRUE;
  650. }
  651. else
  652. SetCursor(LoadCursor(NULL, IDC_ARROW));
  653. }
  654. break;
  655. case WM_SYSCOMMAND:
  656. {
  657. AutoLock autoLock(guard LOCKNAME("VideoOutput::WM_SYSCOMMAND"));
  658. // eat screen saver message when fullscreen
  659. if (((wParam & 0xfff0) == SC_SCREENSAVE || (wParam & 0xfff0) == SC_MONITORPOWER) && config_video_noss &&
  660. video_isVideoPlaying())
  661. {
  662. return -1;
  663. }
  664. }
  665. break;
  666. }
  667. if (m_msgcallback)
  668. {
  669. return m_msgcallback(m_msgcallback_tok, hwnd, uMsg, wParam, lParam);
  670. }
  671. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  672. }
  673. void VideoOutput::fullscreen()
  674. {
  675. AutoLock autoLock(guard LOCKNAME("VideoOutput::fullscreen"));
  676. if (!m_video_output || !m_opened)
  677. return ;
  678. if (is_fs)
  679. return ;
  680. // TODO: let the video renderer handle fullscreen itself, if it can.
  681. /*if (last_fullscreen_exit_time + 250 > GetTickCount()) // gay hack
  682. return ; // dont let you go back and forth too quickly
  683. */
  684. GetWindowRect(hVideoWindow, &oldfsrect); // save the old coordinates
  685. getViewport(&lastfsrect, video_hwnd, 1, NULL);
  686. if (GetParent(hVideoWindow))
  687. {
  688. fs_reparented_rgn = CreateRectRgn(0, 0, 0, 0);
  689. GetWindowRgn(hVideoWindow, fs_reparented_rgn);
  690. fs_reparented = SetParent(hVideoWindow, NULL);
  691. SetWindowRgn(hVideoWindow, NULL, FALSE);
  692. ScreenToClient(fs_reparented, (LPPOINT)&oldfsrect);
  693. ScreenToClient(fs_reparented, ((LPPOINT)&oldfsrect) + 1);
  694. }
  695. is_fullscreen_video = true;
  696. is_fs = true;
  697. //m_video_output->Fullscreen(true);
  698. SetWindowPos(hVideoWindow, HWND_TOPMOST, lastfsrect.left, lastfsrect.top, lastfsrect.right - lastfsrect.left, lastfsrect.bottom - lastfsrect.top, SWP_DRAWFRAME | SWP_NOACTIVATE);
  699. SetFocus(hVideoWindow);
  700. resetSubtitle();
  701. }
  702. extern "C" HWND hExternalVisWindow;
  703. int VideoOutput::openUser(int w, int h, int vflip, double aspectratio, unsigned int fmt)
  704. {
  705. // TODO
  706. return 1;
  707. }
  708. int VideoOutput::open(int w, int h, int vflip, double aspectratio, unsigned int fmt)
  709. {
  710. if (!video_created)
  711. SendMessageW(hVideoWindow, WM_VIDEO_CREATE, 0, 0);
  712. if (!h || !w || !fmt) // check this after creating the video window. some plugins use this call to open the video output early
  713. return 0;
  714. AutoLock autoLock(guard LOCKNAME("VideoOutput::open"));
  715. if (!m_need_change)
  716. stats.IncrementStat(Stats::VIDEOS_PLAYED);
  717. if (hExternalVisWindow)
  718. PostMessageW(hExternalVisWindow, WM_USER + 1666, 1, 15);
  719. m_opened = false;
  720. userVideo = false;
  721. width = w;
  722. height = h;
  723. type = fmt;
  724. aspect = aspectratio;
  725. if (m_video_output)
  726. {
  727. if (type == VIDEO_MAKETYPE('N','O','N','E'))
  728. {
  729. m_opened = true;
  730. PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC);
  731. OpenVideoSize(width, height, aspect);
  732. fs_has_resized = is_fs;
  733. return 0;
  734. }
  735. else if (m_video_output->OpenVideo(w, h, type, vflip, aspect))
  736. {
  737. if (video_palette)
  738. m_video_output->setPalette(video_palette);
  739. video_palette = 0;
  740. DoTheVistaVideoDance();
  741. InvalidateRect(video_hwnd, NULL, TRUE);
  742. m_opened = true;
  743. PostMessageW(hMainWindow, WM_WA_IPC, IPC_CB_MISC_INFO, IPC_CB_MISC);
  744. if (!m_need_change) //don't update size when renegotiating video output
  745. {
  746. OpenVideoSize(width, height, aspect);
  747. fs_has_resized = is_fs;
  748. }
  749. return 0;
  750. }
  751. }
  752. return 1;
  753. }
  754. void VideoOutput::draw(void *frame)
  755. {
  756. if (!frame)
  757. return ;
  758. AutoLock autoLock(guard LOCKNAME("VideoOutput::draw"));
  759. if (m_video_output)
  760. {
  761. m_video_output->displayFrame((const char *)frame, 0, 0);
  762. }
  763. }
  764. extern wchar_t draw_vw_info_lastb[512];
  765. void VideoOutput::close()
  766. {
  767. UpdateText(L"");
  768. AutoLock autoLock(guard);
  769. if (!m_opened)
  770. return ;
  771. m_opened = false;
  772. if (m_video_output)
  773. {
  774. m_video_output->drawSubtitle(0);
  775. m_video_output->close();
  776. }
  777. m_bufferstate = -1;
  778. draw_vw_info_lastb[0] = 0;
  779. input_plugin_thread_safe = false; // reset this
  780. InvalidateRect(video_hwnd, NULL, true);
  781. PostMessageW(hVideoWindow, WM_VIDEO_CLOSE, 0, 0);
  782. }
  783. int VideoOutput::is_fullscreen()
  784. {
  785. return is_fs;
  786. }
  787. void VideoOutput::showStatusMsg(const char *text)
  788. {
  789. AutoLock autoLock(guard);
  790. m_statusmsg = _strdup(text);
  791. PaintLogo(m_bufferstate);
  792. //InvalidateRect(video_hwnd, NULL, TRUE);
  793. }
  794. void VideoOutput::drawSubtitle(SubsItem *item)
  795. {
  796. AutoLock autoLock(guard);
  797. if (item == curSubtitle)
  798. return ;
  799. curSubtitle = item;
  800. if (m_video_output)
  801. m_video_output->drawSubtitle(item);
  802. }
  803. void VideoOutput::resetSubtitle()
  804. {
  805. AutoLock autoLock(guard);
  806. curSubtitle = NULL;
  807. if (m_video_output)
  808. m_video_output->resetSubtitle();
  809. // InvalidateRect(this->getHwnd(), 0, TRUE);
  810. }
  811. void VideoOutput::remove_fullscreen()
  812. {
  813. AutoLock autoLock(guard);
  814. if (!is_fs)
  815. {
  816. is_fullscreen_video = false;
  817. return ;
  818. }
  819. posd->Hide();
  820. posd->ctrlrects_ready = 0; //tofix
  821. if (m_video_output)
  822. {
  823. // m_video_output->Fullscreen(false);
  824. }
  825. resetSubtitle();
  826. is_fs = 0;
  827. if (fs_reparented)
  828. {
  829. SetParent(hVideoWindow, fs_reparented);
  830. SetWindowRgn(hVideoWindow, fs_reparented_rgn, FALSE);
  831. fs_reparented = 0;
  832. SetWindowPos(hVideoWindow, HWND_TOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right - oldfsrect.left, oldfsrect.bottom - oldfsrect.top, SWP_NOACTIVATE | SWP_NOZORDER);
  833. }
  834. else
  835. SetWindowPos(hVideoWindow, config_aot ? HWND_TOPMOST : HWND_NOTOPMOST, oldfsrect.left, oldfsrect.top, oldfsrect.right - oldfsrect.left, oldfsrect.bottom - oldfsrect.top, SWP_NOACTIVATE);
  836. last_fullscreen_exit_time = GetTickCount();
  837. posd->Hide();
  838. if (!m_opened && m_video_output)
  839. {
  840. m_video_output->close();
  841. }
  842. is_fullscreen_video = false;
  843. if (fs_has_resized)
  844. {
  845. fs_has_resized = false;
  846. if (config_video_updsize)
  847. UpdateVideoSize(width, height, aspect);
  848. }
  849. }
  850. void VideoOutput::UpdateVideoSize(int newWidth, int newHeight, double newAspect, int zoom)
  851. {
  852. if (!m_opened)
  853. return;
  854. // fill in default values if we have 0s
  855. if (!newWidth)
  856. newWidth = 320;
  857. if (!newHeight)
  858. newHeight = 240;
  859. switch (zoom)
  860. {
  861. case ID_VIDEOWND_ZOOM200:
  862. newWidth *= 2;
  863. newHeight *= 2;
  864. break;
  865. case ID_VIDEOWND_ZOOM50:
  866. newWidth /= 2;
  867. newHeight /= 2;
  868. break;
  869. }
  870. // establish a minimum window size
  871. if (newWidth < 256)
  872. newWidth = 256;
  873. if (newHeight < 64)
  874. newHeight = 64;
  875. if (newAspect > 0.001) // floating point can be weird about checking == 0
  876. {
  877. if (newAspect < 1.0)
  878. newWidth = (int)((double)newWidth / newAspect);
  879. else
  880. newHeight = (int)((double)newHeight * newAspect);
  881. }
  882. //SendNotifyMessage(hVideoWindow, WM_VIDEO_RESIZE, newWidth, newHeight);
  883. PostMessageW(hVideoWindow, WM_VIDEO_RESIZE, newWidth, newHeight);
  884. }
  885. void VideoOutput::OpenVideoSize(int newWidth, int newHeight, double newAspect)
  886. {
  887. // fill in default values if we have 0s
  888. if (!newWidth)
  889. newWidth = 320;
  890. if (!newHeight)
  891. newHeight = 240;
  892. // establish a minimum window size
  893. if (newWidth < 256)
  894. newWidth = 256;
  895. if (newHeight < 64)
  896. newHeight = 64;
  897. if (newAspect > 0.001) // floating point can be weird about checking == 0
  898. {
  899. if (newAspect < 1.0)
  900. newWidth = (int)((double)newWidth / newAspect);
  901. else
  902. newHeight = (int)((double)newHeight * newAspect);
  903. }
  904. PostMessageW(hVideoWindow, WM_VIDEO_OPEN, newWidth, newHeight);
  905. }
  906. void VideoOutput::SetVideoPosition(int x, int y, int width, int height)
  907. {
  908. AutoLock autoLock(guard);
  909. SetWindowPos(getHwnd(), 0, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
  910. }