Mercurial > mplayer.hg
comparison libvo/vo_kva.c @ 28915:c2baa796c5e5
KVA vo driver for OS/2, patch by KO Myung-Hun, komh chollian net
author | diego |
---|---|
date | Sat, 14 Mar 2009 18:44:58 +0000 |
parents | |
children | 6a0a30aa2b4a |
comparison
equal
deleted
inserted
replaced
28914:f86b4bd1a060 | 28915:c2baa796c5e5 |
---|---|
1 /* | |
2 * OS/2 video output driver | |
3 * | |
4 * Copyright (c) 2007-2009 by KO Myung-Hun (komh@chollian.net) | |
5 * | |
6 * This file is part of MPlayer. | |
7 * | |
8 * MPlayer is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * MPlayer is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License along | |
19 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 */ | |
22 | |
23 #define INCL_WIN | |
24 #define INCL_GPI | |
25 #define INCL_DOS | |
26 #include <os2.h> | |
27 | |
28 #include <mmioos2.h> | |
29 #include <fourcc.h> | |
30 | |
31 #include <stdio.h> | |
32 #include <stdlib.h> | |
33 #include <string.h> | |
34 #include <float.h> | |
35 | |
36 #include <kva.h> | |
37 | |
38 #include "config.h" | |
39 #include "mp_msg.h" | |
40 #include "help_mp.h" | |
41 #include "video_out.h" | |
42 #include "video_out_internal.h" | |
43 #include "aspect.h" | |
44 | |
45 #include "fastmemcpy.h" | |
46 #include "mp_fifo.h" | |
47 #include "osdep/keycodes.h" | |
48 #include "input/input.h" | |
49 #include "input/mouse.h" | |
50 #include "subopt-helper.h" | |
51 #include "sub.h" | |
52 | |
53 #include "cpudetect.h" | |
54 #include "libswscale/swscale.h" | |
55 #include "libmpcodecs/vf_scale.h" | |
56 | |
57 static const vo_info_t info = { | |
58 "SNAP/WarpOverlay!/DIVE video output", | |
59 "kva", | |
60 "KO Myung-Hun <komh@chollian.net>", | |
61 "" | |
62 }; | |
63 | |
64 LIBVO_EXTERN(kva) | |
65 | |
66 #define WC_MPLAYER "WC_MPLAYER" | |
67 | |
68 #define SRC_WIDTH m_int.kvas.szlSrcSize.cx | |
69 #define SRC_HEIGHT m_int.kvas.szlSrcSize.cy | |
70 | |
71 #define HWNDFROMWINID(wid) ((wid) + 0x80000000UL) | |
72 | |
73 static const struct keymap m_vk_map[] = { | |
74 {VK_NEWLINE, KEY_ENTER}, {VK_TAB, KEY_TAB}, {VK_SPACE, ' '}, | |
75 | |
76 // control keys | |
77 {VK_CTRL, KEY_CTRL}, {VK_BACKSPACE, KEY_BS}, | |
78 {VK_DELETE, KEY_DELETE}, {VK_INSERT, KEY_INSERT}, | |
79 {VK_HOME, KEY_HOME}, {VK_END, KEY_END}, | |
80 {VK_PAGEUP, KEY_PAGE_UP}, {VK_PAGEDOWN, KEY_PAGE_DOWN}, | |
81 {VK_ESC, KEY_ESC}, | |
82 | |
83 // cursor keys | |
84 {VK_RIGHT, KEY_RIGHT}, {VK_LEFT, KEY_LEFT}, | |
85 {VK_DOWN, KEY_DOWN}, {VK_UP, KEY_UP}, | |
86 | |
87 // function keys | |
88 {VK_F1, KEY_F+1}, {VK_F2, KEY_F+2}, {VK_F3, KEY_F+3}, {VK_F4, KEY_F+4}, | |
89 {VK_F5, KEY_F+5}, {VK_F6, KEY_F+6}, {VK_F7, KEY_F+7}, {VK_F8, KEY_F+8}, | |
90 {VK_F9, KEY_F+9}, {VK_F10, KEY_F+10}, {VK_F11, KEY_F+11}, {VK_F12, KEY_F+12}, | |
91 | |
92 {0, 0} | |
93 }; | |
94 | |
95 static const struct keymap m_keypad_map[] = { | |
96 // keypad keys | |
97 {0x52, KEY_KP0}, {0x4F, KEY_KP1}, {0x50, KEY_KP2}, {0x51, KEY_KP3}, | |
98 {0x4B, KEY_KP4}, {0x4C, KEY_KP5}, {0x4D, KEY_KP6}, {0x47, KEY_KP7}, | |
99 {0x48, KEY_KP8}, {0x49, KEY_KP9}, {0x53, KEY_KPDEC}, {0x5A, KEY_KPENTER}, | |
100 | |
101 {0, 0} | |
102 }; | |
103 | |
104 static const struct keymap m_mouse_map[] = { | |
105 {WM_BUTTON1DOWN, MOUSE_BTN0}, | |
106 {WM_BUTTON3DOWN, MOUSE_BTN1}, | |
107 {WM_BUTTON2DOWN, MOUSE_BTN2}, | |
108 {WM_BUTTON1DBLCLK, MOUSE_BTN0_DBL}, | |
109 {WM_BUTTON3DBLCLK, MOUSE_BTN1_DBL}, | |
110 {WM_BUTTON2DBLCLK, MOUSE_BTN2_DBL}, | |
111 | |
112 {0, 0} | |
113 }; | |
114 | |
115 struct { | |
116 HAB hab; | |
117 HMQ hmq; | |
118 HWND hwndFrame; | |
119 HWND hwndClient; | |
120 HWND hwndSysMenu; | |
121 HWND hwndTitleBar; | |
122 HWND hwndMinMax; | |
123 FOURCC fcc; | |
124 int iImageFormat; | |
125 int nChromaShift; | |
126 KVASETUP kvas; | |
127 KVACAPS kvac; | |
128 RECTL rclDst; | |
129 int bpp; | |
130 LONG lStride; | |
131 PBYTE pbImage; | |
132 BOOL fFixT23; | |
133 PFNWP pfnwpOldFrame; | |
134 uint8_t *planes[3]; // y = 0, u = 1, v = 2 | |
135 int stride[3]; | |
136 BOOL fHWAccel; | |
137 RECTL rclParent; | |
138 struct SwsContext *sws; | |
139 } m_int; | |
140 | |
141 static inline void setAspectRatio(ULONG ulRatio) | |
142 { | |
143 m_int.kvas.ulRatio = ulRatio; | |
144 kvaSetup(&m_int.kvas); | |
145 } | |
146 | |
147 static int query_format_info(int format, PBOOL pfHWAccel, PFOURCC pfcc, | |
148 int *pbpp, int *pnChromaShift) | |
149 { | |
150 BOOL fHWAccel; | |
151 FOURCC fcc; | |
152 INT bpp; | |
153 INT nChromaShift; | |
154 | |
155 switch (format) { | |
156 case IMGFMT_YV12: | |
157 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YV12; | |
158 fcc = FOURCC_YV12; | |
159 bpp = 1; | |
160 nChromaShift = 1; | |
161 break; | |
162 | |
163 case IMGFMT_YUY2: | |
164 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YUY2; | |
165 fcc = FOURCC_Y422; | |
166 bpp = 2; | |
167 nChromaShift = 0; | |
168 break; | |
169 | |
170 case IMGFMT_YVU9: | |
171 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YVU9; | |
172 fcc = FOURCC_YVU9; | |
173 bpp = 1; | |
174 nChromaShift = 2; | |
175 break; | |
176 | |
177 case IMGFMT_BGR24: | |
178 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR24; | |
179 fcc = FOURCC_BGR3; | |
180 bpp = 3; | |
181 nChromaShift = 0; | |
182 break; | |
183 | |
184 case IMGFMT_BGR16: | |
185 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR16; | |
186 fcc = FOURCC_R565; | |
187 bpp = 2; | |
188 nChromaShift = 0; | |
189 break; | |
190 | |
191 case IMGFMT_BGR15: | |
192 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR15; | |
193 fcc = FOURCC_R555; | |
194 bpp = 2; | |
195 nChromaShift = 0; | |
196 break; | |
197 | |
198 default: | |
199 return 1; | |
200 } | |
201 | |
202 if (pfHWAccel) | |
203 *pfHWAccel = fHWAccel; | |
204 | |
205 if (pfcc) | |
206 *pfcc = fcc; | |
207 | |
208 if (pbpp) | |
209 *pbpp = bpp; | |
210 | |
211 if (pnChromaShift) | |
212 *pnChromaShift = nChromaShift; | |
213 | |
214 return 0; | |
215 } | |
216 | |
217 static void imgCreate(void) | |
218 { | |
219 int size = SRC_HEIGHT * m_int.lStride;; | |
220 | |
221 switch (m_int.iImageFormat) { | |
222 case IMGFMT_YV12: | |
223 size += size / 2; | |
224 break; | |
225 | |
226 case IMGFMT_YVU9: | |
227 size += size / 8; | |
228 break; | |
229 } | |
230 | |
231 m_int.pbImage = malloc(size); | |
232 | |
233 m_int.planes[0] = m_int.pbImage; | |
234 m_int.stride[0] = m_int.lStride; | |
235 | |
236 // YV12 or YVU9 ? | |
237 if (m_int.nChromaShift) { | |
238 m_int.planes[1] = m_int.planes[0] + SRC_HEIGHT * m_int.stride[0]; | |
239 m_int.stride[1] = m_int.stride[0] >> m_int.nChromaShift; | |
240 | |
241 m_int.planes[2] = m_int.planes[1] + | |
242 (SRC_HEIGHT >> m_int.nChromaShift) * m_int.stride[1]; | |
243 m_int.stride[2] = m_int.stride[1]; | |
244 } | |
245 } | |
246 | |
247 static void imgFree(void) | |
248 { | |
249 free(m_int.pbImage); | |
250 | |
251 m_int.pbImage = NULL; | |
252 } | |
253 | |
254 static void imgDisplay(void) | |
255 { | |
256 PVOID pBuffer; | |
257 ULONG ulBPL; | |
258 | |
259 if (!kvaLockBuffer(&pBuffer, &ulBPL)) { | |
260 uint8_t *dst[3]; | |
261 int dstStride[3]; | |
262 | |
263 // Get packed or Y | |
264 dst[0] = pBuffer; | |
265 dstStride[0] = ulBPL; | |
266 | |
267 // YV12 or YVU9 ? | |
268 if (m_int.nChromaShift) { | |
269 // Get V | |
270 dst[2] = dst[0] + SRC_HEIGHT * dstStride[0]; | |
271 dstStride[2] = dstStride[0] >> m_int.nChromaShift; | |
272 | |
273 // Get U | |
274 dst[1] = dst[2] + | |
275 (SRC_HEIGHT >> m_int.nChromaShift ) * dstStride[2]; | |
276 dstStride[1] = dstStride[2]; | |
277 } | |
278 | |
279 if (m_int.fHWAccel) { | |
280 int w, h; | |
281 | |
282 w = m_int.stride[0]; | |
283 h = SRC_HEIGHT; | |
284 | |
285 // Copy packed or Y | |
286 mem2agpcpy_pic(dst[0], m_int.planes[0], w, h, | |
287 dstStride[0], m_int.stride[0]); | |
288 | |
289 // YV12 or YVU9 ? | |
290 if (m_int.nChromaShift) { | |
291 w >>= m_int.nChromaShift; h >>= m_int.nChromaShift; | |
292 | |
293 // Copy U | |
294 mem2agpcpy_pic(dst[1], m_int.planes[1], w, h, | |
295 dstStride[1], m_int.stride[1]); | |
296 | |
297 // Copy V | |
298 mem2agpcpy_pic(dst[2], m_int.planes[2], w, h, | |
299 dstStride[2], m_int.stride[2]); | |
300 } | |
301 } else { | |
302 sws_scale(m_int.sws, m_int.planes, m_int.stride, 0, SRC_HEIGHT, | |
303 dst, dstStride); | |
304 } | |
305 | |
306 kvaUnlockBuffer(); | |
307 } | |
308 } | |
309 | |
310 // Frame window procedure to work around T23 laptop with S3 video card, | |
311 // which supports upscaling only. | |
312 static MRESULT EXPENTRY NewFrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1, | |
313 MPARAM mp2) | |
314 { | |
315 switch (msg) { | |
316 case WM_QUERYTRACKINFO: | |
317 { | |
318 PTRACKINFO pti = (PTRACKINFO)mp2; | |
319 RECTL rcl; | |
320 | |
321 if (vo_fs) | |
322 break; | |
323 | |
324 m_int.pfnwpOldFrame(hwnd, msg, mp1, mp2); | |
325 | |
326 rcl.xLeft = 0; | |
327 rcl.yBottom = 0; | |
328 rcl.xRight = SRC_WIDTH + 1; | |
329 rcl.yTop = SRC_HEIGHT + 1; | |
330 | |
331 WinCalcFrameRect(hwnd, &rcl, FALSE); | |
332 | |
333 pti->ptlMinTrackSize.x = rcl.xRight - rcl.xLeft; | |
334 pti->ptlMinTrackSize.y = rcl.yTop - rcl.yBottom; | |
335 | |
336 pti->ptlMaxTrackSize.x = vo_screenwidth; | |
337 pti->ptlMaxTrackSize.y = vo_screenheight; | |
338 | |
339 return (MRESULT)TRUE; | |
340 } | |
341 | |
342 case WM_ADJUSTWINDOWPOS: | |
343 { | |
344 PSWP pswp = (PSWP)mp1; | |
345 RECTL rcl; | |
346 | |
347 if (vo_fs) | |
348 break; | |
349 | |
350 if (pswp->fl & SWP_SIZE) { | |
351 rcl.xLeft = pswp->x; | |
352 rcl.yBottom = pswp->y; | |
353 rcl.xRight = rcl.xLeft + pswp->cx; | |
354 rcl.yTop = rcl.yBottom + pswp->cy; | |
355 | |
356 WinCalcFrameRect(hwnd, &rcl, TRUE); | |
357 | |
358 if (rcl.xRight - rcl.xLeft <= SRC_WIDTH) | |
359 rcl.xRight = rcl.xLeft + (SRC_WIDTH + 1); | |
360 | |
361 if (rcl.yTop - rcl.yBottom <= SRC_HEIGHT) | |
362 rcl.yTop = rcl.yBottom + (SRC_HEIGHT + 1); | |
363 | |
364 WinCalcFrameRect(hwnd, &rcl, FALSE); | |
365 | |
366 if (rcl.xRight - rcl.xLeft > vo_screenwidth) { | |
367 rcl.xLeft = 0; | |
368 rcl.xRight = vo_screenwidth; | |
369 } | |
370 | |
371 if (rcl.yTop - rcl.yBottom > vo_screenheight) { | |
372 rcl.yBottom = 0; | |
373 rcl.yTop = vo_screenheight; | |
374 } | |
375 | |
376 pswp->fl |= SWP_MOVE; | |
377 pswp->x = rcl.xLeft; | |
378 pswp->y = rcl.yBottom; | |
379 pswp->cx = rcl.xRight - rcl.xLeft; | |
380 pswp->cy = rcl.yTop - rcl.yBottom; | |
381 } | |
382 break; | |
383 } | |
384 } | |
385 | |
386 return m_int.pfnwpOldFrame(hwnd, msg, mp1, mp2); | |
387 } | |
388 | |
389 static MRESULT EXPENTRY WndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) | |
390 { | |
391 // if slave mode, ignore mouse events and deliver them to a parent window | |
392 if (WinID != -1 && | |
393 ((msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) || | |
394 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST))) { | |
395 WinPostMsg(HWNDFROMWINID(WinID), msg, mp1, mp2); | |
396 | |
397 return (MRESULT)TRUE; | |
398 } | |
399 | |
400 switch (msg) { | |
401 case WM_CLOSE: | |
402 mplayer_put_key(KEY_CLOSE_WIN); | |
403 | |
404 return 0; | |
405 | |
406 case WM_CHAR: | |
407 { | |
408 USHORT fsFlags = SHORT1FROMMP(mp1); | |
409 UCHAR uchScan = CHAR4FROMMP(mp1); | |
410 USHORT usCh = SHORT1FROMMP(mp2); | |
411 USHORT usVk = SHORT2FROMMP(mp2); | |
412 int mpkey; | |
413 | |
414 if (fsFlags & KC_KEYUP) | |
415 break; | |
416 | |
417 if (fsFlags & KC_SCANCODE) { | |
418 mpkey = lookup_keymap_table(m_keypad_map, uchScan); | |
419 if (mpkey) { | |
420 // distinguish KEY_KP0 and KEY_KPINS | |
421 if (mpkey == KEY_KP0 && usCh != '0') | |
422 mpkey = KEY_KPINS; | |
423 | |
424 // distinguish KEY_KPDEC and KEY_KPDEL | |
425 if (mpkey == KEY_KPDEC && usCh != '.') | |
426 mpkey = KEY_KPDEL; | |
427 | |
428 mplayer_put_key(mpkey); | |
429 | |
430 return (MRESULT)TRUE; | |
431 } | |
432 } | |
433 | |
434 if (fsFlags & KC_VIRTUALKEY) { | |
435 mpkey = lookup_keymap_table(m_vk_map, usVk); | |
436 if (mpkey) { | |
437 mplayer_put_key(mpkey); | |
438 | |
439 return (MRESULT)TRUE; | |
440 } | |
441 } | |
442 | |
443 if ((fsFlags & KC_CHAR) && !HIBYTE(usCh)) | |
444 mplayer_put_key(usCh); | |
445 | |
446 return (MRESULT)TRUE; | |
447 } | |
448 | |
449 case WM_BUTTON1DOWN: | |
450 case WM_BUTTON3DOWN: | |
451 case WM_BUTTON2DOWN: | |
452 case WM_BUTTON1DBLCLK: | |
453 case WM_BUTTON3DBLCLK: | |
454 case WM_BUTTON2DBLCLK: | |
455 if (WinQueryFocus(HWND_DESKTOP) != hwnd) | |
456 WinSetFocus(HWND_DESKTOP, hwnd); | |
457 else if (!vo_nomouse_input) | |
458 mplayer_put_key(lookup_keymap_table(m_mouse_map, msg)); | |
459 | |
460 return (MRESULT)TRUE; | |
461 | |
462 case WM_PAINT: | |
463 { | |
464 HPS hps; | |
465 RECTL rcl, rclDst; | |
466 PRECTL prcl = NULL; | |
467 HRGN hrgn, hrgnDst; | |
468 RGNRECT rgnCtl; | |
469 | |
470 // get a current movie area | |
471 kvaAdjustDstRect(&m_int.kvas.rclSrcRect, &rclDst); | |
472 | |
473 // get a current invalidated area | |
474 hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl); | |
475 | |
476 // create a region for an invalidated area | |
477 hrgn = GpiCreateRegion(hps, 1, &rcl); | |
478 // create a region for a movie area | |
479 hrgnDst = GpiCreateRegion(hps, 1, &rclDst); | |
480 | |
481 // exclude a movie area from an invalidated area | |
482 GpiCombineRegion(hps, hrgn, hrgn, hrgnDst, CRGN_DIFF); | |
483 | |
484 // get rectangles from the region | |
485 rgnCtl.ircStart = 1; | |
486 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT; | |
487 GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, NULL); | |
488 | |
489 if (rgnCtl.crcReturned > 0) { | |
490 rgnCtl.crc = rgnCtl.crcReturned; | |
491 prcl = malloc(sizeof(RECTL) * rgnCtl.crcReturned); | |
492 } | |
493 | |
494 // draw black bar if needed | |
495 if (prcl && GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, prcl)) { | |
496 int i; | |
497 | |
498 for (i = 0; i < rgnCtl.crcReturned; i++) | |
499 WinFillRect(hps, &prcl[i], CLR_BLACK); | |
500 } | |
501 | |
502 free(prcl); | |
503 | |
504 GpiDestroyRegion(hps, hrgnDst); | |
505 GpiDestroyRegion(hps, hrgn); | |
506 | |
507 WinEndPaint(hps); | |
508 | |
509 return 0; | |
510 } | |
511 } | |
512 | |
513 return WinDefWindowProc(hwnd, msg, mp1, mp2); | |
514 } | |
515 | |
516 // Change process type from VIO to PM to use PM APIs. | |
517 static void morphToPM(void) | |
518 { | |
519 PPIB pib; | |
520 | |
521 DosGetInfoBlocks(NULL, &pib); | |
522 | |
523 // Change flag from VIO to PM: | |
524 if (pib->pib_ultype == 2) | |
525 pib->pib_ultype = 3; | |
526 } | |
527 | |
528 static int preinit(const char *arg) | |
529 { | |
530 HWND hwndParent; | |
531 ULONG flFrameFlags; | |
532 ULONG kvaMode = 0; | |
533 | |
534 int fUseSnap = 0; | |
535 int fUseWO = 0; | |
536 int fUseDive = 0; | |
537 int fFixT23 = 0; | |
538 | |
539 const opt_t subopts[] = { | |
540 {"snap", OPT_ARG_BOOL, &fUseSnap, NULL}, | |
541 {"wo", OPT_ARG_BOOL, &fUseWO, NULL}, | |
542 {"dive", OPT_ARG_BOOL, &fUseDive, NULL}, | |
543 {"t23", OPT_ARG_BOOL, &fFixT23, NULL}, | |
544 {NULL, 0, NULL, NULL} | |
545 }; | |
546 | |
547 PCSZ pcszVideoModeStr[3] = {"DIVE", "WarpOverlay!", "SNAP"}; | |
548 | |
549 if (subopt_parse(arg, subopts) != 0) | |
550 return -1; | |
551 | |
552 morphToPM(); | |
553 | |
554 memset(&m_int, 0, sizeof(m_int)); | |
555 | |
556 m_int.hab = WinInitialize(0); | |
557 m_int.hmq = WinCreateMsgQueue(m_int.hab, 0); | |
558 | |
559 WinRegisterClass(m_int.hab, | |
560 WC_MPLAYER, | |
561 WndProc, | |
562 CS_SIZEREDRAW | CS_MOVENOTIFY, | |
563 sizeof(PVOID)); | |
564 | |
565 if (WinID == -1) { | |
566 hwndParent = HWND_DESKTOP; | |
567 flFrameFlags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX | | |
568 FCF_SIZEBORDER | FCF_TASKLIST; | |
569 } else { | |
570 hwndParent = HWNDFROMWINID(WinID); | |
571 flFrameFlags = 0; | |
572 } | |
573 | |
574 m_int.hwndFrame = | |
575 WinCreateStdWindow(hwndParent, // parent window handle | |
576 WS_VISIBLE, // frame window style | |
577 &flFrameFlags, // window style | |
578 WC_MPLAYER, // class name | |
579 "", // window title | |
580 0L, // default client style | |
581 NULLHANDLE, // resource in exe file | |
582 1, // frame window id | |
583 &m_int.hwndClient); // client window handle | |
584 | |
585 if (m_int.hwndFrame == NULLHANDLE) | |
586 return -1; | |
587 | |
588 m_int.hwndSysMenu = WinWindowFromID(m_int.hwndFrame, FID_SYSMENU); | |
589 m_int.hwndTitleBar = WinWindowFromID(m_int.hwndFrame, FID_TITLEBAR); | |
590 m_int.hwndMinMax = WinWindowFromID(m_int.hwndFrame, FID_MINMAX); | |
591 | |
592 m_int.fFixT23 = fFixT23; | |
593 | |
594 if (m_int.fFixT23) | |
595 m_int.pfnwpOldFrame = WinSubclassWindow(m_int.hwndFrame, | |
596 NewFrameWndProc); | |
597 | |
598 if (!!fUseSnap + !!fUseWO + !!fUseDive > 1) | |
599 mp_msg(MSGT_VO, MSGL_WARN,"KVA: Multiple mode specified!!!\n"); | |
600 | |
601 if (fUseSnap) | |
602 kvaMode = KVAM_SNAP; | |
603 else if (fUseWO) | |
604 kvaMode = KVAM_WO; | |
605 else if (fUseDive) | |
606 kvaMode = KVAM_DIVE; | |
607 else | |
608 kvaMode = KVAM_AUTO; | |
609 | |
610 if (kvaInit(kvaMode, m_int.hwndClient, vo_colorkey)) { | |
611 mp_msg(MSGT_VO, MSGL_ERR, "KVA: Init failed!!!\n"); | |
612 | |
613 return -1; | |
614 } | |
615 | |
616 kvaCaps(&m_int.kvac); | |
617 | |
618 mp_msg(MSGT_VO, MSGL_V, "KVA: Selected video mode = %s\n", | |
619 pcszVideoModeStr[m_int.kvac.ulMode - 1]); | |
620 | |
621 kvaDisableScreenSaver(); | |
622 | |
623 // Might cause PM DLLs to be loaded which incorrectly enable SIG_FPE, | |
624 // so mask off all floating-point exceptions. | |
625 _control87(MCW_EM, MCW_EM); | |
626 | |
627 return 0; | |
628 } | |
629 | |
630 static void uninit(void) | |
631 { | |
632 kvaEnableScreenSaver(); | |
633 | |
634 imgFree(); | |
635 | |
636 sws_freeContext(m_int.sws); | |
637 | |
638 if (m_int.hwndFrame != NULLHANDLE) { | |
639 kvaResetAttr(); | |
640 kvaDone(); | |
641 | |
642 if (m_int.fFixT23) | |
643 WinSubclassWindow(m_int.hwndFrame, m_int.pfnwpOldFrame); | |
644 | |
645 WinDestroyWindow(m_int.hwndFrame); | |
646 } | |
647 | |
648 WinDestroyMsgQueue(m_int.hmq); | |
649 WinTerminate(m_int.hab); | |
650 } | |
651 | |
652 static int config(uint32_t width, uint32_t height, | |
653 uint32_t d_width, uint32_t d_height, | |
654 uint32_t flags, char *title, uint32_t format) | |
655 { | |
656 RECTL rcl; | |
657 | |
658 mp_msg(MSGT_VO, MSGL_V, | |
659 "KVA: Using 0x%X (%s) image format, vo_config_count = %d\n", | |
660 format, vo_format_name(format), vo_config_count); | |
661 | |
662 imgFree(); | |
663 | |
664 if (query_format_info(format, &m_int.fHWAccel, &m_int.fcc, &m_int.bpp, | |
665 &m_int.nChromaShift)) | |
666 return 1; | |
667 | |
668 m_int.iImageFormat = format; | |
669 | |
670 // if there is no hw accel for given format, | |
671 // try any format supported by hw accel | |
672 if (!m_int.fHWAccel) { | |
673 int dstFormat = 0; | |
674 | |
675 sws_freeContext(m_int.sws); | |
676 | |
677 if (m_int.kvac.ulInputFormatFlags & KVAF_YV12) | |
678 dstFormat = IMGFMT_YV12; | |
679 else if (m_int.kvac.ulInputFormatFlags & KVAF_YUY2) | |
680 dstFormat = IMGFMT_YUY2; | |
681 else if (m_int.kvac.ulInputFormatFlags & KVAF_YVU9) | |
682 dstFormat = IMGFMT_YVU9; | |
683 else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR24) | |
684 dstFormat = IMGFMT_BGR24; | |
685 else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR16) | |
686 dstFormat = IMGFMT_BGR16; | |
687 else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR15) | |
688 dstFormat = IMGFMT_BGR15; | |
689 | |
690 if (query_format_info(dstFormat, NULL, &m_int.fcc, NULL, NULL)) | |
691 return 1; | |
692 | |
693 m_int.sws = sws_getContextFromCmdLine(width, height, format, | |
694 width, height, dstFormat); | |
695 } | |
696 | |
697 mp_msg(MSGT_VO, MSGL_V, "KVA: Selected FOURCC = %.4s\n", (char *)&m_int.fcc); | |
698 | |
699 m_int.kvas.ulLength = sizeof(KVASETUP); | |
700 m_int.kvas.szlSrcSize.cx = width; | |
701 m_int.kvas.szlSrcSize.cy = height; | |
702 m_int.kvas.rclSrcRect.xLeft = 0; | |
703 m_int.kvas.rclSrcRect.yTop = 0; | |
704 m_int.kvas.rclSrcRect.xRight = width; | |
705 m_int.kvas.rclSrcRect.yBottom = height; | |
706 m_int.kvas.ulRatio = vo_keepaspect ? KVAR_FORCEANY : KVAR_NONE; | |
707 m_int.kvas.ulAspectWidth = d_width; | |
708 m_int.kvas.ulAspectHeight = d_height; | |
709 m_int.kvas.fccSrcColor = m_int.fcc; | |
710 m_int.kvas.fDither = TRUE; | |
711 | |
712 if (kvaSetup(&m_int.kvas)) { | |
713 mp_msg(MSGT_VO, MSGL_ERR, "KVA: Setup failed!!!\n"); | |
714 | |
715 return 1; | |
716 } | |
717 | |
718 m_int.lStride = width * m_int.bpp; | |
719 | |
720 imgCreate(); | |
721 | |
722 if (WinID == -1) { | |
723 WinSetWindowText(m_int.hwndFrame, title); | |
724 | |
725 // initialize 'vo_fs' only once at first config() call | |
726 if (vo_config_count == 0) | |
727 vo_fs = flags & VOFLAG_FULLSCREEN; | |
728 | |
729 // workaround for T23 laptop with S3 Video by Franz Bakan | |
730 if (!vo_fs && m_int.fFixT23) { | |
731 d_width++; | |
732 d_height++; | |
733 } | |
734 | |
735 m_int.rclDst.xLeft = ((LONG)vo_screenwidth - (LONG)d_width) / 2; | |
736 m_int.rclDst.yBottom = ((LONG)vo_screenheight - (LONG)d_height) / 2; | |
737 m_int.rclDst.xRight = m_int.rclDst.xLeft + d_width; | |
738 m_int.rclDst.yTop = m_int.rclDst.yBottom + d_height; | |
739 | |
740 if (vo_fs) { | |
741 d_width = vo_screenwidth; | |
742 d_height = vo_screenheight; | |
743 | |
744 // when -fs option is used without this, title bar is not highlighted | |
745 WinSetActiveWindow(HWND_DESKTOP, m_int.hwndFrame); | |
746 | |
747 WinSetParent(m_int.hwndSysMenu, HWND_OBJECT, FALSE); | |
748 WinSetParent(m_int.hwndTitleBar, HWND_OBJECT, FALSE); | |
749 WinSetParent(m_int.hwndMinMax, HWND_OBJECT, FALSE); | |
750 | |
751 setAspectRatio(KVAR_FORCEANY); | |
752 } | |
753 | |
754 rcl.xLeft = ((LONG)vo_screenwidth - (LONG)d_width) / 2; | |
755 rcl.yBottom = ((LONG)vo_screenheight - (LONG)d_height) /2 ; | |
756 rcl.xRight = rcl.xLeft + d_width; | |
757 rcl.yTop = rcl.yBottom + d_height; | |
758 } else { | |
759 vo_fs = 0; | |
760 | |
761 WinQueryWindowRect(HWNDFROMWINID(WinID), &m_int.rclDst); | |
762 rcl = m_int.rclDst; | |
763 } | |
764 | |
765 WinCalcFrameRect(m_int.hwndFrame, &rcl, FALSE); | |
766 | |
767 WinSetWindowPos(m_int.hwndFrame, HWND_TOP, | |
768 rcl.xLeft, rcl.yBottom, | |
769 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, | |
770 SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW | | |
771 (WinID == -1 ? SWP_ACTIVATE : 0)); | |
772 | |
773 WinInvalidateRect(m_int.hwndFrame, NULL, TRUE); | |
774 | |
775 return 0; | |
776 } | |
777 | |
778 static uint32_t get_image(mp_image_t *mpi) | |
779 { | |
780 if (m_int.iImageFormat != mpi->imgfmt) | |
781 return VO_FALSE; | |
782 | |
783 if (mpi->type == MP_IMGTYPE_STATIC || mpi->type == MP_IMGTYPE_TEMP) { | |
784 if (mpi->flags & MP_IMGFLAG_PLANAR) { | |
785 mpi->planes[1] = m_int.planes[1]; | |
786 mpi->planes[2] = m_int.planes[2]; | |
787 | |
788 mpi->stride[1] = m_int.stride[1]; | |
789 mpi->stride[2] = m_int.stride[2]; | |
790 } | |
791 | |
792 mpi->planes[0] = m_int.planes[0]; | |
793 mpi->stride[0] = m_int.stride[0]; | |
794 mpi->flags |= MP_IMGFLAG_DIRECT; | |
795 | |
796 return VO_TRUE; | |
797 } | |
798 | |
799 return VO_FALSE; | |
800 } | |
801 | |
802 static uint32_t draw_image(mp_image_t *mpi) | |
803 { | |
804 // if -dr or -slices then do nothing: | |
805 if (mpi->flags & (MP_IMGFLAG_DIRECT | MP_IMGFLAG_DRAW_CALLBACK)) | |
806 return VO_TRUE; | |
807 | |
808 draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, mpi->x, mpi->y); | |
809 | |
810 return VO_TRUE; | |
811 } | |
812 | |
813 static int query_format(uint32_t format) | |
814 { | |
815 BOOL fHWAccel; | |
816 int res; | |
817 | |
818 if (query_format_info(format, &fHWAccel, NULL, NULL, NULL)) | |
819 return 0; | |
820 | |
821 res = VFCAP_CSP_SUPPORTED | VFCAP_OSD; | |
822 if (fHWAccel) { | |
823 res |= VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP; | |
824 | |
825 if (!m_int.fFixT23) | |
826 res |= VFCAP_HWSCALE_DOWN; | |
827 } | |
828 | |
829 return res; | |
830 } | |
831 | |
832 static int fs_toggle(void) | |
833 { | |
834 RECTL rcl; | |
835 | |
836 vo_fs = !vo_fs; | |
837 | |
838 if (vo_fs) { | |
839 SWP swp; | |
840 | |
841 WinQueryWindowPos(m_int.hwndFrame, &swp); | |
842 m_int.rclDst.xLeft = swp.x; | |
843 m_int.rclDst.yBottom = swp.y; | |
844 m_int.rclDst.xRight = m_int.rclDst.xLeft + swp.cx; | |
845 m_int.rclDst.yTop = m_int.rclDst.yBottom + swp.cy; | |
846 WinCalcFrameRect(m_int.hwndFrame, &m_int.rclDst, TRUE); | |
847 | |
848 if (WinID != -1) | |
849 WinSetParent(m_int.hwndFrame, HWND_DESKTOP, FALSE); | |
850 | |
851 WinSetParent(m_int.hwndSysMenu, HWND_OBJECT, FALSE); | |
852 WinSetParent(m_int.hwndTitleBar, HWND_OBJECT, FALSE); | |
853 WinSetParent(m_int.hwndMinMax, HWND_OBJECT, FALSE); | |
854 | |
855 rcl.xLeft = 0; | |
856 rcl.yBottom = 0; | |
857 rcl.xRight = vo_screenwidth; | |
858 rcl.yTop = vo_screenheight; | |
859 | |
860 setAspectRatio(KVAR_FORCEANY); | |
861 } else { | |
862 if (WinID != -1) | |
863 WinSetParent(m_int.hwndFrame, HWNDFROMWINID(WinID), TRUE); | |
864 | |
865 WinSetParent(m_int.hwndSysMenu, m_int.hwndFrame, FALSE); | |
866 WinSetParent(m_int.hwndTitleBar, m_int.hwndFrame, FALSE); | |
867 WinSetParent(m_int.hwndMinMax, m_int.hwndFrame, FALSE); | |
868 | |
869 rcl = m_int.rclDst; | |
870 | |
871 setAspectRatio(vo_keepaspect ? KVAR_FORCEANY : KVAR_NONE); | |
872 } | |
873 | |
874 WinCalcFrameRect(m_int.hwndFrame, &rcl, FALSE); | |
875 | |
876 WinSetWindowPos(m_int.hwndFrame, HWND_TOP, | |
877 rcl.xLeft, rcl.yBottom, | |
878 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, | |
879 SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW | | |
880 (WinID == -1 ? SWP_ACTIVATE : 0)); | |
881 | |
882 return VO_TRUE; | |
883 } | |
884 | |
885 static int color_ctrl_set(char *what, int value) | |
886 { | |
887 ULONG ulAttr; | |
888 ULONG ulValue; | |
889 | |
890 if (!strcmp(what, "brightness")) | |
891 ulAttr = KVAA_BRIGHTNESS; | |
892 else if (!strcmp(what, "contrast")) | |
893 ulAttr = KVAA_CONTRAST; | |
894 else if (!strcmp(what, "hue")) | |
895 ulAttr = KVAA_HUE; | |
896 else if (!strcmp(what, "saturation")) | |
897 ulAttr = KVAA_SATURATION; | |
898 else | |
899 return VO_NOTIMPL; | |
900 | |
901 ulValue = (value + 100) * 255 / 200; | |
902 | |
903 if (kvaSetAttr(ulAttr, &ulValue)) | |
904 return VO_NOTIMPL; | |
905 | |
906 return VO_TRUE; | |
907 } | |
908 | |
909 static int color_ctrl_get(char *what, int *value) | |
910 { | |
911 ULONG ulAttr; | |
912 ULONG ulValue; | |
913 | |
914 if (!strcmp(what, "brightness")) | |
915 ulAttr = KVAA_BRIGHTNESS; | |
916 else if (!strcmp(what, "contrast")) | |
917 ulAttr = KVAA_CONTRAST; | |
918 else if (!strcmp(what, "hue")) | |
919 ulAttr = KVAA_HUE; | |
920 else if (!strcmp(what, "saturation")) | |
921 ulAttr = KVAA_SATURATION; | |
922 else | |
923 return VO_NOTIMPL; | |
924 | |
925 if (kvaQueryAttr(ulAttr, &ulValue)) | |
926 return VO_NOTIMPL; | |
927 | |
928 // add 1 to adjust range | |
929 *value = ((ulValue + 1) * 200 / 255) - 100; | |
930 | |
931 return VO_TRUE; | |
932 } | |
933 | |
934 static int control(uint32_t request, void *data, ...) | |
935 { | |
936 switch (request) { | |
937 case VOCTRL_GET_IMAGE: | |
938 return get_image(data); | |
939 | |
940 case VOCTRL_DRAW_IMAGE: | |
941 return draw_image(data); | |
942 | |
943 case VOCTRL_QUERY_FORMAT: | |
944 return query_format(*(uint32_t *)data); | |
945 | |
946 case VOCTRL_FULLSCREEN: | |
947 return fs_toggle(); | |
948 | |
949 case VOCTRL_SET_EQUALIZER: | |
950 { | |
951 va_list ap; | |
952 int value; | |
953 | |
954 va_start(ap, data); | |
955 value = va_arg(ap, int); | |
956 va_end(ap); | |
957 | |
958 return color_ctrl_set(data, value); | |
959 } | |
960 | |
961 case VOCTRL_GET_EQUALIZER: | |
962 { | |
963 va_list ap; | |
964 int *value; | |
965 | |
966 va_start(ap, data); | |
967 value = va_arg(ap, int *); | |
968 va_end(ap); | |
969 | |
970 return color_ctrl_get(data, value); | |
971 } | |
972 | |
973 case VOCTRL_UPDATE_SCREENINFO: | |
974 vo_screenwidth = m_int.kvac.cxScreen; | |
975 vo_screenheight = m_int.kvac.cyScreen; | |
976 | |
977 aspect_save_screenres(vo_screenwidth, vo_screenheight); | |
978 | |
979 return VO_TRUE; | |
980 } | |
981 | |
982 return VO_NOTIMPL; | |
983 } | |
984 | |
985 static int draw_frame(uint8_t *src[]) | |
986 { | |
987 return VO_ERROR; | |
988 } | |
989 | |
990 static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y) | |
991 { | |
992 uint8_t *s; | |
993 uint8_t *d; | |
994 | |
995 // copy packed or Y | |
996 d = m_int.planes[0] + m_int.stride[0] * y + x; | |
997 s = src[0]; | |
998 mem2agpcpy_pic(d, s, w * m_int.bpp, h, m_int.stride[0], stride[0]); | |
999 | |
1000 // YV12 or YVU9 | |
1001 if (m_int.nChromaShift) { | |
1002 w >>= m_int.nChromaShift; h >>= m_int.nChromaShift; | |
1003 x >>= m_int.nChromaShift; y >>= m_int.nChromaShift; | |
1004 | |
1005 // copy U | |
1006 d = m_int.planes[1] + m_int.stride[1] * y + x; | |
1007 s = src[1]; | |
1008 mem2agpcpy_pic(d, s, w, h, m_int.stride[1], stride[1]); | |
1009 | |
1010 // copy V | |
1011 d = m_int.planes[2] + m_int.stride[2] * y + x; | |
1012 s = src[2]; | |
1013 mem2agpcpy_pic(d, s, w, h, m_int.stride[2], stride[2]); | |
1014 } | |
1015 | |
1016 return 0; | |
1017 } | |
1018 | |
1019 #define vo_draw_alpha(imgfmt) \ | |
1020 vo_draw_alpha_##imgfmt(w, h, src, srca, stride, \ | |
1021 m_int.planes[0] + m_int.stride[0] * y0 + m_int.bpp * x0, \ | |
1022 m_int.stride[0]) | |
1023 | |
1024 static void draw_alpha(int x0, int y0, int w, int h, | |
1025 unsigned char *src, unsigned char *srca, int stride) | |
1026 { | |
1027 switch (m_int.iImageFormat) { | |
1028 case IMGFMT_YV12: | |
1029 case IMGFMT_YVU9: | |
1030 vo_draw_alpha(yv12); | |
1031 break; | |
1032 | |
1033 case IMGFMT_YUY2: | |
1034 vo_draw_alpha(yuy2); | |
1035 break; | |
1036 | |
1037 case IMGFMT_BGR24: | |
1038 vo_draw_alpha(rgb24); | |
1039 break; | |
1040 | |
1041 case IMGFMT_BGR16: | |
1042 vo_draw_alpha(rgb16); | |
1043 break; | |
1044 | |
1045 case IMGFMT_BGR15: | |
1046 vo_draw_alpha(rgb15); | |
1047 break; | |
1048 } | |
1049 } | |
1050 | |
1051 static void draw_osd(void) | |
1052 { | |
1053 vo_draw_text(SRC_WIDTH, SRC_HEIGHT, draw_alpha); | |
1054 } | |
1055 | |
1056 static void flip_page(void) | |
1057 { | |
1058 imgDisplay(); | |
1059 } | |
1060 | |
1061 static void check_events(void) | |
1062 { | |
1063 QMSG qm; | |
1064 | |
1065 // On slave mode, we need to change our window size according to a | |
1066 // parent window size | |
1067 if (WinID != -1) { | |
1068 RECTL rcl; | |
1069 | |
1070 WinQueryWindowRect(HWNDFROMWINID(WinID), &rcl); | |
1071 | |
1072 if (rcl.xLeft != m_int.rclParent.xLeft || | |
1073 rcl.yBottom != m_int.rclParent.yBottom || | |
1074 rcl.xRight != m_int.rclParent.xRight || | |
1075 rcl.yTop != m_int.rclParent.yTop) { | |
1076 WinSetWindowPos(m_int.hwndFrame, NULLHANDLE, | |
1077 rcl.xLeft, rcl.yBottom, | |
1078 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, | |
1079 SWP_SIZE | SWP_MOVE); | |
1080 | |
1081 m_int.rclParent = rcl; | |
1082 } | |
1083 } | |
1084 | |
1085 while (WinPeekMsg(m_int.hab, &qm, NULLHANDLE, 0, 0, PM_REMOVE)) | |
1086 WinDispatchMsg(m_int.hab, &qm); | |
1087 } |