vo_gl: add new vo name "gl_sdl" to make SDL+GL mode available
[mplayer.git] / libvo / vo_kva.c
blob878911c4388f1d39602b53107d1c13716ce97c89
1 /*
2 * OS/2 video output driver
4 * Copyright (c) 2007-2009 by KO Myung-Hun (komh@chollian.net)
6 * This file is part of MPlayer.
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.
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.
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.
23 #define INCL_WIN
24 #define INCL_GPI
25 #define INCL_DOS
26 #include <os2.h>
28 #include <mmioos2.h>
29 #include <fourcc.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <float.h>
36 #include <kva.h>
38 #include "config.h"
39 #include "mp_msg.h"
40 #include "video_out.h"
41 #include "video_out_internal.h"
42 #include "aspect.h"
44 #include "fastmemcpy.h"
45 #include "mp_fifo.h"
46 #include "input/keycodes.h"
47 #include "input/input.h"
48 #include "subopt-helper.h"
49 #include "sub/sub.h"
51 #include "cpudetect.h"
52 #include "libswscale/swscale.h"
53 #include "libmpcodecs/vf_scale.h"
55 static const vo_info_t info = {
56 "SNAP/WarpOverlay!/DIVE video output",
57 "kva",
58 "KO Myung-Hun <komh@chollian.net>",
62 const LIBVO_EXTERN(kva)
64 #define WC_MPLAYER "WC_MPLAYER"
66 #define SRC_WIDTH m_int.kvas.szlSrcSize.cx
67 #define SRC_HEIGHT m_int.kvas.szlSrcSize.cy
69 #define HWNDFROMWINID(wid) ((wid) + 0x80000000UL)
71 static const struct mp_keymap m_vk_map[] = {
72 {VK_NEWLINE, KEY_ENTER}, {VK_TAB, KEY_TAB}, {VK_SPACE, ' '},
74 // control keys
75 {VK_CTRL, KEY_CTRL}, {VK_BACKSPACE, KEY_BS},
76 {VK_DELETE, KEY_DELETE}, {VK_INSERT, KEY_INSERT},
77 {VK_HOME, KEY_HOME}, {VK_END, KEY_END},
78 {VK_PAGEUP, KEY_PAGE_UP}, {VK_PAGEDOWN, KEY_PAGE_DOWN},
79 {VK_ESC, KEY_ESC},
81 // cursor keys
82 {VK_RIGHT, KEY_RIGHT}, {VK_LEFT, KEY_LEFT},
83 {VK_DOWN, KEY_DOWN}, {VK_UP, KEY_UP},
85 // function keys
86 {VK_F1, KEY_F+1}, {VK_F2, KEY_F+2}, {VK_F3, KEY_F+3}, {VK_F4, KEY_F+4},
87 {VK_F5, KEY_F+5}, {VK_F6, KEY_F+6}, {VK_F7, KEY_F+7}, {VK_F8, KEY_F+8},
88 {VK_F9, KEY_F+9}, {VK_F10, KEY_F+10}, {VK_F11, KEY_F+11}, {VK_F12, KEY_F+12},
90 {0, 0}
93 static const struct mp_keymap m_keypad_map[] = {
94 // keypad keys
95 {0x52, KEY_KP0}, {0x4F, KEY_KP1}, {0x50, KEY_KP2}, {0x51, KEY_KP3},
96 {0x4B, KEY_KP4}, {0x4C, KEY_KP5}, {0x4D, KEY_KP6}, {0x47, KEY_KP7},
97 {0x48, KEY_KP8}, {0x49, KEY_KP9}, {0x53, KEY_KPDEC}, {0x5A, KEY_KPENTER},
99 {0, 0}
102 static const struct mp_keymap m_mouse_map[] = {
103 {WM_BUTTON1DOWN, MOUSE_BTN0},
104 {WM_BUTTON3DOWN, MOUSE_BTN1},
105 {WM_BUTTON2DOWN, MOUSE_BTN2},
106 {WM_BUTTON1DBLCLK, MOUSE_BTN0_DBL},
107 {WM_BUTTON3DBLCLK, MOUSE_BTN1_DBL},
108 {WM_BUTTON2DBLCLK, MOUSE_BTN2_DBL},
110 {0, 0}
113 struct {
114 HAB hab;
115 HMQ hmq;
116 HWND hwndFrame;
117 HWND hwndClient;
118 HWND hwndSysMenu;
119 HWND hwndTitleBar;
120 HWND hwndMinMax;
121 FOURCC fcc;
122 int iImageFormat;
123 int nChromaShift;
124 KVASETUP kvas;
125 KVACAPS kvac;
126 RECTL rclDst;
127 int bpp;
128 LONG lStride;
129 PBYTE pbImage;
130 BOOL fFixT23;
131 PFNWP pfnwpOldFrame;
132 uint8_t *planes[MP_MAX_PLANES]; // y = 0, u = 1, v = 2
133 int stride[MP_MAX_PLANES];
134 BOOL fHWAccel;
135 RECTL rclParent;
136 struct SwsContext *sws;
137 } m_int;
139 static inline void setAspectRatio(ULONG ulRatio)
141 ULONG ulValue;
142 int i;
144 m_int.kvas.ulRatio = ulRatio;
145 kvaSetup(&m_int.kvas);
147 // Setup initializes all attributes, so need to restore them.
148 for (i = 0; i < KVAA_LAST; i++) {
149 kvaQueryAttr(i, &ulValue);
150 kvaSetAttr(i, &ulValue);
154 static int query_format_info(int format, PBOOL pfHWAccel, PFOURCC pfcc,
155 int *pbpp, int *pnChromaShift)
157 BOOL fHWAccel;
158 FOURCC fcc;
159 INT bpp;
160 INT nChromaShift;
162 switch (format) {
163 case IMGFMT_YV12:
164 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YV12;
165 fcc = FOURCC_YV12;
166 bpp = 1;
167 nChromaShift = 1;
168 break;
170 case IMGFMT_YUY2:
171 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YUY2;
172 fcc = FOURCC_Y422;
173 bpp = 2;
174 nChromaShift = 0;
175 break;
177 case IMGFMT_YVU9:
178 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YVU9;
179 fcc = FOURCC_YVU9;
180 bpp = 1;
181 nChromaShift = 2;
182 break;
184 case IMGFMT_BGR24:
185 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR24;
186 fcc = FOURCC_BGR3;
187 bpp = 3;
188 nChromaShift = 0;
189 break;
191 case IMGFMT_BGR16:
192 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR16;
193 fcc = FOURCC_R565;
194 bpp = 2;
195 nChromaShift = 0;
196 break;
198 case IMGFMT_BGR15:
199 fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR15;
200 fcc = FOURCC_R555;
201 bpp = 2;
202 nChromaShift = 0;
203 break;
205 default:
206 return 1;
209 if (pfHWAccel)
210 *pfHWAccel = fHWAccel;
212 if (pfcc)
213 *pfcc = fcc;
215 if (pbpp)
216 *pbpp = bpp;
218 if (pnChromaShift)
219 *pnChromaShift = nChromaShift;
221 return 0;
224 static void imgCreate(void)
226 int size = SRC_HEIGHT * m_int.lStride;;
228 switch (m_int.iImageFormat) {
229 case IMGFMT_YV12:
230 size += size / 2;
231 break;
233 case IMGFMT_YVU9:
234 size += size / 8;
235 break;
238 m_int.pbImage = malloc(size);
240 memset(m_int.planes, 0, sizeof(m_int.planes));
241 memset(m_int.stride, 0, sizeof(m_int.stride));
242 m_int.planes[0] = m_int.pbImage;
243 m_int.stride[0] = m_int.lStride;
245 // YV12 or YVU9 ?
246 if (m_int.nChromaShift) {
247 m_int.planes[1] = m_int.planes[0] + SRC_HEIGHT * m_int.stride[0];
248 m_int.stride[1] = m_int.stride[0] >> m_int.nChromaShift;
250 m_int.planes[2] = m_int.planes[1] +
251 (SRC_HEIGHT >> m_int.nChromaShift) * m_int.stride[1];
252 m_int.stride[2] = m_int.stride[1];
256 static void imgFree(void)
258 free(m_int.pbImage);
260 m_int.pbImage = NULL;
263 static void imgDisplay(void)
265 PVOID pBuffer;
266 ULONG ulBPL;
268 if (!kvaLockBuffer(&pBuffer, &ulBPL)) {
269 uint8_t *dst[MP_MAX_PLANES] = {NULL};
270 int dstStride[MP_MAX_PLANES] = {0};
272 // Get packed or Y
273 dst[0] = pBuffer;
274 dstStride[0] = ulBPL;
276 // YV12 or YVU9 ?
277 if (m_int.nChromaShift) {
278 // Get V
279 dst[2] = dst[0] + SRC_HEIGHT * dstStride[0];
280 dstStride[2] = dstStride[0] >> m_int.nChromaShift;
282 // Get U
283 dst[1] = dst[2] +
284 (SRC_HEIGHT >> m_int.nChromaShift ) * dstStride[2];
285 dstStride[1] = dstStride[2];
288 if (m_int.fHWAccel) {
289 int w, h;
291 w = m_int.stride[0];
292 h = SRC_HEIGHT;
294 // Copy packed or Y
295 mem2agpcpy_pic(dst[0], m_int.planes[0], w, h,
296 dstStride[0], m_int.stride[0]);
298 // YV12 or YVU9 ?
299 if (m_int.nChromaShift) {
300 w >>= m_int.nChromaShift; h >>= m_int.nChromaShift;
302 // Copy U
303 mem2agpcpy_pic(dst[1], m_int.planes[1], w, h,
304 dstStride[1], m_int.stride[1]);
306 // Copy V
307 mem2agpcpy_pic(dst[2], m_int.planes[2], w, h,
308 dstStride[2], m_int.stride[2]);
310 } else {
311 sws_scale(m_int.sws, m_int.planes, m_int.stride, 0, SRC_HEIGHT,
312 dst, dstStride);
315 kvaUnlockBuffer();
319 // Frame window procedure to work around T23 laptop with S3 video card,
320 // which supports upscaling only.
321 static MRESULT EXPENTRY NewFrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1,
322 MPARAM mp2)
324 switch (msg) {
325 case WM_QUERYTRACKINFO:
327 PTRACKINFO pti = (PTRACKINFO)mp2;
328 RECTL rcl;
330 if (vo_fs)
331 break;
333 m_int.pfnwpOldFrame(hwnd, msg, mp1, mp2);
335 rcl.xLeft = 0;
336 rcl.yBottom = 0;
337 rcl.xRight = SRC_WIDTH + 1;
338 rcl.yTop = SRC_HEIGHT + 1;
340 WinCalcFrameRect(hwnd, &rcl, FALSE);
342 pti->ptlMinTrackSize.x = rcl.xRight - rcl.xLeft;
343 pti->ptlMinTrackSize.y = rcl.yTop - rcl.yBottom;
345 pti->ptlMaxTrackSize.x = vo_screenwidth;
346 pti->ptlMaxTrackSize.y = vo_screenheight;
348 return (MRESULT)TRUE;
351 case WM_ADJUSTWINDOWPOS:
353 PSWP pswp = (PSWP)mp1;
354 RECTL rcl;
356 if (vo_fs)
357 break;
359 if (pswp->fl & SWP_SIZE) {
360 rcl.xLeft = pswp->x;
361 rcl.yBottom = pswp->y;
362 rcl.xRight = rcl.xLeft + pswp->cx;
363 rcl.yTop = rcl.yBottom + pswp->cy;
365 WinCalcFrameRect(hwnd, &rcl, TRUE);
367 if (rcl.xRight - rcl.xLeft <= SRC_WIDTH)
368 rcl.xRight = rcl.xLeft + (SRC_WIDTH + 1);
370 if (rcl.yTop - rcl.yBottom <= SRC_HEIGHT)
371 rcl.yTop = rcl.yBottom + (SRC_HEIGHT + 1);
373 WinCalcFrameRect(hwnd, &rcl, FALSE);
375 if (rcl.xRight - rcl.xLeft > vo_screenwidth) {
376 rcl.xLeft = 0;
377 rcl.xRight = vo_screenwidth;
380 if (rcl.yTop - rcl.yBottom > vo_screenheight) {
381 rcl.yBottom = 0;
382 rcl.yTop = vo_screenheight;
385 pswp->fl |= SWP_MOVE;
386 pswp->x = rcl.xLeft;
387 pswp->y = rcl.yBottom;
388 pswp->cx = rcl.xRight - rcl.xLeft;
389 pswp->cy = rcl.yTop - rcl.yBottom;
391 break;
395 return m_int.pfnwpOldFrame(hwnd, msg, mp1, mp2);
398 static MRESULT EXPENTRY WndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
400 // if slave mode, ignore mouse events and deliver them to a parent window
401 if (WinID != -1 &&
402 ((msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
403 (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST))) {
404 WinPostMsg(HWNDFROMWINID(WinID), msg, mp1, mp2);
406 return (MRESULT)TRUE;
409 switch (msg) {
410 case WM_CLOSE:
411 mplayer_put_key(KEY_CLOSE_WIN);
413 return 0;
415 case WM_CHAR:
417 USHORT fsFlags = SHORT1FROMMP(mp1);
418 UCHAR uchScan = CHAR4FROMMP(mp1);
419 USHORT usCh = SHORT1FROMMP(mp2);
420 USHORT usVk = SHORT2FROMMP(mp2);
421 int mpkey;
423 if (fsFlags & KC_KEYUP)
424 break;
426 if (fsFlags & KC_SCANCODE) {
427 mpkey = lookup_keymap_table(m_keypad_map, uchScan);
428 if (mpkey) {
429 // distinguish KEY_KP0 and KEY_KPINS
430 if (mpkey == KEY_KP0 && usCh != '0')
431 mpkey = KEY_KPINS;
433 // distinguish KEY_KPDEC and KEY_KPDEL
434 if (mpkey == KEY_KPDEC && usCh != '.')
435 mpkey = KEY_KPDEL;
437 mplayer_put_key(mpkey);
439 return (MRESULT)TRUE;
443 if (fsFlags & KC_VIRTUALKEY) {
444 mpkey = lookup_keymap_table(m_vk_map, usVk);
445 if (mpkey) {
446 mplayer_put_key(mpkey);
448 return (MRESULT)TRUE;
452 if ((fsFlags & KC_CHAR) && !HIBYTE(usCh))
453 mplayer_put_key(usCh);
455 return (MRESULT)TRUE;
458 case WM_BUTTON1DOWN:
459 case WM_BUTTON3DOWN:
460 case WM_BUTTON2DOWN:
461 case WM_BUTTON1DBLCLK:
462 case WM_BUTTON3DBLCLK:
463 case WM_BUTTON2DBLCLK:
464 if (WinQueryFocus(HWND_DESKTOP) != hwnd)
465 WinSetFocus(HWND_DESKTOP, hwnd);
466 else if (!vo_nomouse_input)
467 mplayer_put_key(lookup_keymap_table(m_mouse_map, msg));
469 return (MRESULT)TRUE;
471 case WM_PAINT:
473 HPS hps;
474 RECTL rcl, rclDst;
475 PRECTL prcl = NULL;
476 HRGN hrgn, hrgnDst;
477 RGNRECT rgnCtl;
479 // get a current movie area
480 kvaAdjustDstRect(&m_int.kvas.rclSrcRect, &rclDst);
482 // get a current invalidated area
483 hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl);
485 // create a region for an invalidated area
486 hrgn = GpiCreateRegion(hps, 1, &rcl);
487 // create a region for a movie area
488 hrgnDst = GpiCreateRegion(hps, 1, &rclDst);
490 // exclude a movie area from an invalidated area
491 GpiCombineRegion(hps, hrgn, hrgn, hrgnDst, CRGN_DIFF);
493 // get rectangles from the region
494 rgnCtl.ircStart = 1;
495 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT;
496 GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, NULL);
498 if (rgnCtl.crcReturned > 0) {
499 rgnCtl.crc = rgnCtl.crcReturned;
500 prcl = malloc(sizeof(RECTL) * rgnCtl.crcReturned);
503 // draw black bar if needed
504 if (prcl && GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, prcl)) {
505 int i;
507 for (i = 0; i < rgnCtl.crcReturned; i++)
508 WinFillRect(hps, &prcl[i], CLR_BLACK);
511 free(prcl);
513 GpiDestroyRegion(hps, hrgnDst);
514 GpiDestroyRegion(hps, hrgn);
516 WinEndPaint(hps);
518 return 0;
522 return WinDefWindowProc(hwnd, msg, mp1, mp2);
525 // Change process type from VIO to PM to use PM APIs.
526 static void morphToPM(void)
528 PPIB pib;
530 DosGetInfoBlocks(NULL, &pib);
532 // Change flag from VIO to PM:
533 if (pib->pib_ultype == 2)
534 pib->pib_ultype = 3;
537 static int preinit(const char *arg)
539 HWND hwndParent;
540 ULONG flFrameFlags;
541 ULONG kvaMode = 0;
543 int fUseSnap = 0;
544 int fUseWO = 0;
545 int fUseDive = 0;
546 int fFixT23 = 0;
548 const opt_t subopts[] = {
549 {"snap", OPT_ARG_BOOL, &fUseSnap, NULL},
550 {"wo", OPT_ARG_BOOL, &fUseWO, NULL},
551 {"dive", OPT_ARG_BOOL, &fUseDive, NULL},
552 {"t23", OPT_ARG_BOOL, &fFixT23, NULL},
553 {NULL, 0, NULL, NULL}
556 PCSZ pcszVideoModeStr[3] = {"DIVE", "WarpOverlay!", "SNAP"};
558 if (subopt_parse(arg, subopts) != 0)
559 return -1;
561 morphToPM();
563 memset(&m_int, 0, sizeof(m_int));
565 m_int.hab = WinInitialize(0);
566 m_int.hmq = WinCreateMsgQueue(m_int.hab, 0);
568 WinRegisterClass(m_int.hab,
569 WC_MPLAYER,
570 WndProc,
571 CS_SIZEREDRAW | CS_MOVENOTIFY,
572 sizeof(PVOID));
574 if (WinID == -1) {
575 hwndParent = HWND_DESKTOP;
576 flFrameFlags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX |
577 FCF_SIZEBORDER | FCF_TASKLIST;
578 } else {
579 ULONG ulStyle;
581 hwndParent = HWNDFROMWINID(WinID);
582 flFrameFlags = 0;
584 // Prevent a parent window from painting over our window
585 ulStyle = WinQueryWindowULong(hwndParent, QWL_STYLE);
586 WinSetWindowULong(hwndParent, QWL_STYLE, ulStyle | WS_CLIPCHILDREN);
589 m_int.hwndFrame =
590 WinCreateStdWindow(hwndParent, // parent window handle
591 WS_VISIBLE, // frame window style
592 &flFrameFlags, // window style
593 WC_MPLAYER, // class name
594 "", // window title
595 0L, // default client style
596 NULLHANDLE, // resource in exe file
597 1, // frame window id
598 &m_int.hwndClient); // client window handle
600 if (m_int.hwndFrame == NULLHANDLE)
601 return -1;
603 m_int.hwndSysMenu = WinWindowFromID(m_int.hwndFrame, FID_SYSMENU);
604 m_int.hwndTitleBar = WinWindowFromID(m_int.hwndFrame, FID_TITLEBAR);
605 m_int.hwndMinMax = WinWindowFromID(m_int.hwndFrame, FID_MINMAX);
607 m_int.fFixT23 = fFixT23;
609 if (m_int.fFixT23)
610 m_int.pfnwpOldFrame = WinSubclassWindow(m_int.hwndFrame,
611 NewFrameWndProc);
613 if (!!fUseSnap + !!fUseWO + !!fUseDive > 1)
614 mp_msg(MSGT_VO, MSGL_WARN,"KVA: Multiple mode specified!!!\n");
616 if (fUseSnap)
617 kvaMode = KVAM_SNAP;
618 else if (fUseWO)
619 kvaMode = KVAM_WO;
620 else if (fUseDive)
621 kvaMode = KVAM_DIVE;
622 else
623 kvaMode = KVAM_AUTO;
625 if (kvaInit(kvaMode, m_int.hwndClient, vo_colorkey)) {
626 mp_msg(MSGT_VO, MSGL_ERR, "KVA: Init failed!!!\n");
628 return -1;
631 kvaCaps(&m_int.kvac);
633 mp_msg(MSGT_VO, MSGL_V, "KVA: Selected video mode = %s\n",
634 pcszVideoModeStr[m_int.kvac.ulMode - 1]);
636 kvaDisableScreenSaver();
638 // Might cause PM DLLs to be loaded which incorrectly enable SIG_FPE,
639 // so mask off all floating-point exceptions.
640 _control87(MCW_EM, MCW_EM);
642 return 0;
645 static void uninit(void)
647 kvaEnableScreenSaver();
649 imgFree();
651 sws_freeContext(m_int.sws);
653 if (m_int.hwndFrame != NULLHANDLE) {
654 kvaResetAttr();
655 kvaDone();
657 if (m_int.fFixT23)
658 WinSubclassWindow(m_int.hwndFrame, m_int.pfnwpOldFrame);
660 WinDestroyWindow(m_int.hwndFrame);
663 WinDestroyMsgQueue(m_int.hmq);
664 WinTerminate(m_int.hab);
667 static int config(uint32_t width, uint32_t height,
668 uint32_t d_width, uint32_t d_height,
669 uint32_t flags, char *title, uint32_t format)
671 RECTL rcl;
673 mp_msg(MSGT_VO, MSGL_V,
674 "KVA: Using 0x%X (%s) image format, vo_config_count = %d\n",
675 format, vo_format_name(format), vo_config_count);
677 imgFree();
679 if (query_format_info(format, &m_int.fHWAccel, &m_int.fcc, &m_int.bpp,
680 &m_int.nChromaShift))
681 return 1;
683 m_int.iImageFormat = format;
685 // if there is no hw accel for given format,
686 // try any format supported by hw accel
687 if (!m_int.fHWAccel) {
688 int dstFormat = 0;
690 sws_freeContext(m_int.sws);
692 if (m_int.kvac.ulInputFormatFlags & KVAF_YV12)
693 dstFormat = IMGFMT_YV12;
694 else if (m_int.kvac.ulInputFormatFlags & KVAF_YUY2)
695 dstFormat = IMGFMT_YUY2;
696 else if (m_int.kvac.ulInputFormatFlags & KVAF_YVU9)
697 dstFormat = IMGFMT_YVU9;
698 else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR24)
699 dstFormat = IMGFMT_BGR24;
700 else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR16)
701 dstFormat = IMGFMT_BGR16;
702 else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR15)
703 dstFormat = IMGFMT_BGR15;
705 if (query_format_info(dstFormat, NULL, &m_int.fcc, NULL, NULL))
706 return 1;
708 m_int.sws = sws_getContextFromCmdLine(width, height, format,
709 width, height, dstFormat);
712 mp_msg(MSGT_VO, MSGL_V, "KVA: Selected FOURCC = %.4s\n", (char *)&m_int.fcc);
714 m_int.kvas.ulLength = sizeof(KVASETUP);
715 m_int.kvas.szlSrcSize.cx = width;
716 m_int.kvas.szlSrcSize.cy = height;
717 m_int.kvas.rclSrcRect.xLeft = 0;
718 m_int.kvas.rclSrcRect.yTop = 0;
719 m_int.kvas.rclSrcRect.xRight = width;
720 m_int.kvas.rclSrcRect.yBottom = height;
721 m_int.kvas.ulRatio = vo_keepaspect ? KVAR_FORCEANY : KVAR_NONE;
722 m_int.kvas.ulAspectWidth = d_width;
723 m_int.kvas.ulAspectHeight = d_height;
724 m_int.kvas.fccSrcColor = m_int.fcc;
725 m_int.kvas.fDither = TRUE;
727 if (kvaSetup(&m_int.kvas)) {
728 mp_msg(MSGT_VO, MSGL_ERR, "KVA: Setup failed!!!\n");
730 return 1;
733 m_int.lStride = width * m_int.bpp;
735 imgCreate();
737 if (WinID == -1) {
738 WinSetWindowText(m_int.hwndFrame, title);
740 // initialize 'vo_fs' only once at first config() call
741 if (vo_config_count == 0)
742 vo_fs = flags & VOFLAG_FULLSCREEN;
744 // workaround for T23 laptop with S3 Video by Franz Bakan
745 if (!vo_fs && m_int.fFixT23) {
746 d_width++;
747 d_height++;
750 m_int.rclDst.xLeft = ((LONG)vo_screenwidth - (LONG)d_width) / 2;
751 m_int.rclDst.yBottom = ((LONG)vo_screenheight - (LONG)d_height) / 2;
752 m_int.rclDst.xRight = m_int.rclDst.xLeft + d_width;
753 m_int.rclDst.yTop = m_int.rclDst.yBottom + d_height;
755 if (vo_fs) {
756 d_width = vo_screenwidth;
757 d_height = vo_screenheight;
759 // when -fs option is used without this, title bar is not highlighted
760 WinSetActiveWindow(HWND_DESKTOP, m_int.hwndFrame);
762 WinSetParent(m_int.hwndSysMenu, HWND_OBJECT, FALSE);
763 WinSetParent(m_int.hwndTitleBar, HWND_OBJECT, FALSE);
764 WinSetParent(m_int.hwndMinMax, HWND_OBJECT, FALSE);
766 setAspectRatio(KVAR_FORCEANY);
769 rcl.xLeft = ((LONG)vo_screenwidth - (LONG)d_width) / 2;
770 rcl.yBottom = ((LONG)vo_screenheight - (LONG)d_height) /2 ;
771 rcl.xRight = rcl.xLeft + d_width;
772 rcl.yTop = rcl.yBottom + d_height;
773 } else {
774 vo_fs = 0;
776 WinQueryWindowRect(HWNDFROMWINID(WinID), &m_int.rclDst);
777 rcl = m_int.rclDst;
780 WinCalcFrameRect(m_int.hwndFrame, &rcl, FALSE);
782 WinSetWindowPos(m_int.hwndFrame, HWND_TOP,
783 rcl.xLeft, rcl.yBottom,
784 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
785 SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW |
786 (WinID == -1 ? SWP_ACTIVATE : 0));
788 WinInvalidateRect(m_int.hwndFrame, NULL, TRUE);
790 return 0;
793 static uint32_t get_image(mp_image_t *mpi)
795 if (m_int.iImageFormat != mpi->imgfmt)
796 return VO_FALSE;
798 if (mpi->type == MP_IMGTYPE_STATIC || mpi->type == MP_IMGTYPE_TEMP) {
799 if (mpi->flags & MP_IMGFLAG_PLANAR) {
800 mpi->planes[1] = m_int.planes[1];
801 mpi->planes[2] = m_int.planes[2];
803 mpi->stride[1] = m_int.stride[1];
804 mpi->stride[2] = m_int.stride[2];
807 mpi->planes[0] = m_int.planes[0];
808 mpi->stride[0] = m_int.stride[0];
809 mpi->flags |= MP_IMGFLAG_DIRECT;
811 return VO_TRUE;
814 return VO_FALSE;
817 static uint32_t draw_image(mp_image_t *mpi)
819 // if -dr or -slices then do nothing:
820 if (mpi->flags & (MP_IMGFLAG_DIRECT | MP_IMGFLAG_DRAW_CALLBACK))
821 return VO_TRUE;
823 draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, mpi->x, mpi->y);
825 return VO_TRUE;
828 static int query_format(uint32_t format)
830 BOOL fHWAccel;
831 int res;
833 if (query_format_info(format, &fHWAccel, NULL, NULL, NULL))
834 return 0;
836 res = VFCAP_CSP_SUPPORTED | VFCAP_OSD;
837 if (fHWAccel) {
838 res |= VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP;
840 if (!m_int.fFixT23)
841 res |= VFCAP_HWSCALE_DOWN;
844 return res;
847 static int fs_toggle(void)
849 RECTL rcl;
851 vo_fs = !vo_fs;
853 if (vo_fs) {
854 SWP swp;
856 WinQueryWindowPos(m_int.hwndFrame, &swp);
857 m_int.rclDst.xLeft = swp.x;
858 m_int.rclDst.yBottom = swp.y;
859 m_int.rclDst.xRight = m_int.rclDst.xLeft + swp.cx;
860 m_int.rclDst.yTop = m_int.rclDst.yBottom + swp.cy;
861 WinCalcFrameRect(m_int.hwndFrame, &m_int.rclDst, TRUE);
863 if (WinID != -1)
864 WinSetParent(m_int.hwndFrame, HWND_DESKTOP, FALSE);
866 WinSetParent(m_int.hwndSysMenu, HWND_OBJECT, FALSE);
867 WinSetParent(m_int.hwndTitleBar, HWND_OBJECT, FALSE);
868 WinSetParent(m_int.hwndMinMax, HWND_OBJECT, FALSE);
870 rcl.xLeft = 0;
871 rcl.yBottom = 0;
872 rcl.xRight = vo_screenwidth;
873 rcl.yTop = vo_screenheight;
875 setAspectRatio(KVAR_FORCEANY);
876 } else {
877 if (WinID != -1)
878 WinSetParent(m_int.hwndFrame, HWNDFROMWINID(WinID), TRUE);
880 WinSetParent(m_int.hwndSysMenu, m_int.hwndFrame, FALSE);
881 WinSetParent(m_int.hwndTitleBar, m_int.hwndFrame, FALSE);
882 WinSetParent(m_int.hwndMinMax, m_int.hwndFrame, FALSE);
884 rcl = m_int.rclDst;
886 setAspectRatio(vo_keepaspect ? KVAR_FORCEANY : KVAR_NONE);
889 WinCalcFrameRect(m_int.hwndFrame, &rcl, FALSE);
891 WinSetWindowPos(m_int.hwndFrame, HWND_TOP,
892 rcl.xLeft, rcl.yBottom,
893 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
894 SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW |
895 (WinID == -1 ? SWP_ACTIVATE : 0));
897 return VO_TRUE;
900 static int color_ctrl_set(char *what, int value)
902 ULONG ulAttr;
903 ULONG ulValue;
905 if (!strcmp(what, "brightness"))
906 ulAttr = KVAA_BRIGHTNESS;
907 else if (!strcmp(what, "contrast"))
908 ulAttr = KVAA_CONTRAST;
909 else if (!strcmp(what, "hue"))
910 ulAttr = KVAA_HUE;
911 else if (!strcmp(what, "saturation"))
912 ulAttr = KVAA_SATURATION;
913 else
914 return VO_NOTIMPL;
916 ulValue = (value + 100) * 255 / 200;
918 if (kvaSetAttr(ulAttr, &ulValue))
919 return VO_NOTIMPL;
921 return VO_TRUE;
924 static int color_ctrl_get(char *what, int *value)
926 ULONG ulAttr;
927 ULONG ulValue;
929 if (!strcmp(what, "brightness"))
930 ulAttr = KVAA_BRIGHTNESS;
931 else if (!strcmp(what, "contrast"))
932 ulAttr = KVAA_CONTRAST;
933 else if (!strcmp(what, "hue"))
934 ulAttr = KVAA_HUE;
935 else if (!strcmp(what, "saturation"))
936 ulAttr = KVAA_SATURATION;
937 else
938 return VO_NOTIMPL;
940 if (kvaQueryAttr(ulAttr, &ulValue))
941 return VO_NOTIMPL;
943 // add 1 to adjust range
944 *value = ((ulValue + 1) * 200 / 255) - 100;
946 return VO_TRUE;
949 static int control(uint32_t request, void *data)
951 switch (request) {
952 case VOCTRL_GET_IMAGE:
953 return get_image(data);
955 case VOCTRL_DRAW_IMAGE:
956 return draw_image(data);
958 case VOCTRL_QUERY_FORMAT:
959 return query_format(*(uint32_t *)data);
961 case VOCTRL_FULLSCREEN:
962 return fs_toggle();
964 case VOCTRL_SET_EQUALIZER:
966 struct voctrl_set_equalizer_args *args = data;
967 color_ctrl_set(args->name, args->value);
970 case VOCTRL_GET_EQUALIZER:
972 struct voctrl_get_equalizer_args *args = data;
973 return color_ctrl_get(args->name, args->valueptr);
976 case VOCTRL_UPDATE_SCREENINFO:
977 vo_screenwidth = m_int.kvac.cxScreen;
978 vo_screenheight = m_int.kvac.cyScreen;
980 aspect_save_screenres(vo_screenwidth, vo_screenheight);
982 return VO_TRUE;
985 return VO_NOTIMPL;
988 static int draw_frame(uint8_t *src[])
990 return VO_ERROR;
993 static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y)
995 uint8_t *s;
996 uint8_t *d;
998 // copy packed or Y
999 d = m_int.planes[0] + m_int.stride[0] * y + x;
1000 s = src[0];
1001 mem2agpcpy_pic(d, s, w * m_int.bpp, h, m_int.stride[0], stride[0]);
1003 // YV12 or YVU9
1004 if (m_int.nChromaShift) {
1005 w >>= m_int.nChromaShift; h >>= m_int.nChromaShift;
1006 x >>= m_int.nChromaShift; y >>= m_int.nChromaShift;
1008 // copy U
1009 d = m_int.planes[1] + m_int.stride[1] * y + x;
1010 s = src[1];
1011 mem2agpcpy_pic(d, s, w, h, m_int.stride[1], stride[1]);
1013 // copy V
1014 d = m_int.planes[2] + m_int.stride[2] * y + x;
1015 s = src[2];
1016 mem2agpcpy_pic(d, s, w, h, m_int.stride[2], stride[2]);
1019 return 0;
1022 #define vo_draw_alpha(imgfmt) \
1023 vo_draw_alpha_##imgfmt(w, h, src, srca, stride, \
1024 m_int.planes[0] + m_int.stride[0] * y0 + m_int.bpp * x0, \
1025 m_int.stride[0])
1027 static void draw_alpha(int x0, int y0, int w, int h,
1028 unsigned char *src, unsigned char *srca, int stride)
1030 switch (m_int.iImageFormat) {
1031 case IMGFMT_YV12:
1032 case IMGFMT_YVU9:
1033 vo_draw_alpha(yv12);
1034 break;
1036 case IMGFMT_YUY2:
1037 vo_draw_alpha(yuy2);
1038 break;
1040 case IMGFMT_BGR24:
1041 vo_draw_alpha(rgb24);
1042 break;
1044 case IMGFMT_BGR16:
1045 vo_draw_alpha(rgb16);
1046 break;
1048 case IMGFMT_BGR15:
1049 vo_draw_alpha(rgb15);
1050 break;
1054 static void draw_osd(void)
1056 vo_draw_text(SRC_WIDTH, SRC_HEIGHT, draw_alpha);
1059 static void flip_page(void)
1061 imgDisplay();
1064 static void check_events(void)
1066 QMSG qm;
1068 // On slave mode, we need to change our window size according to a
1069 // parent window size
1070 if (WinID != -1) {
1071 RECTL rcl;
1073 WinQueryWindowRect(HWNDFROMWINID(WinID), &rcl);
1075 if (rcl.xLeft != m_int.rclParent.xLeft ||
1076 rcl.yBottom != m_int.rclParent.yBottom ||
1077 rcl.xRight != m_int.rclParent.xRight ||
1078 rcl.yTop != m_int.rclParent.yTop) {
1079 WinSetWindowPos(m_int.hwndFrame, NULLHANDLE,
1080 rcl.xLeft, rcl.yBottom,
1081 rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1082 SWP_SIZE | SWP_MOVE);
1084 m_int.rclParent = rcl;
1088 while (WinPeekMsg(m_int.hab, &qm, NULLHANDLE, 0, 0, PM_REMOVE))
1089 WinDispatchMsg(m_int.hab, &qm);