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.
40 #include "video_out.h"
41 #include "video_out_internal.h"
44 #include "fastmemcpy.h"
46 #include "osdep/keycodes.h"
47 #include "input/input.h"
48 #include "input/mouse.h"
49 #include "subopt-helper.h"
52 #include "cpudetect.h"
53 #include "libswscale/swscale.h"
54 #include "libmpcodecs/vf_scale.h"
56 static const vo_info_t info
= {
57 "SNAP/WarpOverlay!/DIVE video output",
59 "KO Myung-Hun <komh@chollian.net>",
63 const LIBVO_EXTERN(kva
)
65 #define WC_MPLAYER "WC_MPLAYER"
67 #define SRC_WIDTH m_int.kvas.szlSrcSize.cx
68 #define SRC_HEIGHT m_int.kvas.szlSrcSize.cy
70 #define HWNDFROMWINID(wid) ((wid) + 0x80000000UL)
72 static const struct mp_keymap m_vk_map
[] = {
73 {VK_NEWLINE
, KEY_ENTER
}, {VK_TAB
, KEY_TAB
}, {VK_SPACE
, ' '},
76 {VK_CTRL
, KEY_CTRL
}, {VK_BACKSPACE
, KEY_BS
},
77 {VK_DELETE
, KEY_DELETE
}, {VK_INSERT
, KEY_INSERT
},
78 {VK_HOME
, KEY_HOME
}, {VK_END
, KEY_END
},
79 {VK_PAGEUP
, KEY_PAGE_UP
}, {VK_PAGEDOWN
, KEY_PAGE_DOWN
},
83 {VK_RIGHT
, KEY_RIGHT
}, {VK_LEFT
, KEY_LEFT
},
84 {VK_DOWN
, KEY_DOWN
}, {VK_UP
, KEY_UP
},
87 {VK_F1
, KEY_F
+1}, {VK_F2
, KEY_F
+2}, {VK_F3
, KEY_F
+3}, {VK_F4
, KEY_F
+4},
88 {VK_F5
, KEY_F
+5}, {VK_F6
, KEY_F
+6}, {VK_F7
, KEY_F
+7}, {VK_F8
, KEY_F
+8},
89 {VK_F9
, KEY_F
+9}, {VK_F10
, KEY_F
+10}, {VK_F11
, KEY_F
+11}, {VK_F12
, KEY_F
+12},
94 static const struct mp_keymap m_keypad_map
[] = {
96 {0x52, KEY_KP0
}, {0x4F, KEY_KP1
}, {0x50, KEY_KP2
}, {0x51, KEY_KP3
},
97 {0x4B, KEY_KP4
}, {0x4C, KEY_KP5
}, {0x4D, KEY_KP6
}, {0x47, KEY_KP7
},
98 {0x48, KEY_KP8
}, {0x49, KEY_KP9
}, {0x53, KEY_KPDEC
}, {0x5A, KEY_KPENTER
},
103 static const struct mp_keymap m_mouse_map
[] = {
104 {WM_BUTTON1DOWN
, MOUSE_BTN0
},
105 {WM_BUTTON3DOWN
, MOUSE_BTN1
},
106 {WM_BUTTON2DOWN
, MOUSE_BTN2
},
107 {WM_BUTTON1DBLCLK
, MOUSE_BTN0_DBL
},
108 {WM_BUTTON3DBLCLK
, MOUSE_BTN1_DBL
},
109 {WM_BUTTON2DBLCLK
, MOUSE_BTN2_DBL
},
133 uint8_t *planes
[MP_MAX_PLANES
]; // y = 0, u = 1, v = 2
134 int stride
[MP_MAX_PLANES
];
137 struct SwsContext
*sws
;
140 static inline void setAspectRatio(ULONG ulRatio
)
145 m_int
.kvas
.ulRatio
= ulRatio
;
146 kvaSetup(&m_int
.kvas
);
148 // Setup initializes all attributes, so need to restore them.
149 for (i
= 0; i
< KVAA_LAST
; i
++) {
150 kvaQueryAttr(i
, &ulValue
);
151 kvaSetAttr(i
, &ulValue
);
155 static int query_format_info(int format
, PBOOL pfHWAccel
, PFOURCC pfcc
,
156 int *pbpp
, int *pnChromaShift
)
165 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YV12
;
172 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YUY2
;
179 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YVU9
;
186 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR24
;
193 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR16
;
200 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR15
;
211 *pfHWAccel
= fHWAccel
;
220 *pnChromaShift
= nChromaShift
;
225 static void imgCreate(void)
227 int size
= SRC_HEIGHT
* m_int
.lStride
;;
229 switch (m_int
.iImageFormat
) {
239 m_int
.pbImage
= malloc(size
);
241 memset(m_int
.planes
, 0, sizeof(m_int
.planes
));
242 memset(m_int
.stride
, 0, sizeof(m_int
.stride
));
243 m_int
.planes
[0] = m_int
.pbImage
;
244 m_int
.stride
[0] = m_int
.lStride
;
247 if (m_int
.nChromaShift
) {
248 m_int
.planes
[1] = m_int
.planes
[0] + SRC_HEIGHT
* m_int
.stride
[0];
249 m_int
.stride
[1] = m_int
.stride
[0] >> m_int
.nChromaShift
;
251 m_int
.planes
[2] = m_int
.planes
[1] +
252 (SRC_HEIGHT
>> m_int
.nChromaShift
) * m_int
.stride
[1];
253 m_int
.stride
[2] = m_int
.stride
[1];
257 static void imgFree(void)
261 m_int
.pbImage
= NULL
;
264 static void imgDisplay(void)
269 if (!kvaLockBuffer(&pBuffer
, &ulBPL
)) {
270 uint8_t *dst
[MP_MAX_PLANES
] = {NULL
};
271 int dstStride
[MP_MAX_PLANES
] = {0};
275 dstStride
[0] = ulBPL
;
278 if (m_int
.nChromaShift
) {
280 dst
[2] = dst
[0] + SRC_HEIGHT
* dstStride
[0];
281 dstStride
[2] = dstStride
[0] >> m_int
.nChromaShift
;
285 (SRC_HEIGHT
>> m_int
.nChromaShift
) * dstStride
[2];
286 dstStride
[1] = dstStride
[2];
289 if (m_int
.fHWAccel
) {
296 mem2agpcpy_pic(dst
[0], m_int
.planes
[0], w
, h
,
297 dstStride
[0], m_int
.stride
[0]);
300 if (m_int
.nChromaShift
) {
301 w
>>= m_int
.nChromaShift
; h
>>= m_int
.nChromaShift
;
304 mem2agpcpy_pic(dst
[1], m_int
.planes
[1], w
, h
,
305 dstStride
[1], m_int
.stride
[1]);
308 mem2agpcpy_pic(dst
[2], m_int
.planes
[2], w
, h
,
309 dstStride
[2], m_int
.stride
[2]);
312 sws_scale(m_int
.sws
, m_int
.planes
, m_int
.stride
, 0, SRC_HEIGHT
,
320 // Frame window procedure to work around T23 laptop with S3 video card,
321 // which supports upscaling only.
322 static MRESULT EXPENTRY
NewFrameWndProc(HWND hwnd
, ULONG msg
, MPARAM mp1
,
326 case WM_QUERYTRACKINFO
:
328 PTRACKINFO pti
= (PTRACKINFO
)mp2
;
334 m_int
.pfnwpOldFrame(hwnd
, msg
, mp1
, mp2
);
338 rcl
.xRight
= SRC_WIDTH
+ 1;
339 rcl
.yTop
= SRC_HEIGHT
+ 1;
341 WinCalcFrameRect(hwnd
, &rcl
, FALSE
);
343 pti
->ptlMinTrackSize
.x
= rcl
.xRight
- rcl
.xLeft
;
344 pti
->ptlMinTrackSize
.y
= rcl
.yTop
- rcl
.yBottom
;
346 pti
->ptlMaxTrackSize
.x
= vo_screenwidth
;
347 pti
->ptlMaxTrackSize
.y
= vo_screenheight
;
349 return (MRESULT
)TRUE
;
352 case WM_ADJUSTWINDOWPOS
:
354 PSWP pswp
= (PSWP
)mp1
;
360 if (pswp
->fl
& SWP_SIZE
) {
362 rcl
.yBottom
= pswp
->y
;
363 rcl
.xRight
= rcl
.xLeft
+ pswp
->cx
;
364 rcl
.yTop
= rcl
.yBottom
+ pswp
->cy
;
366 WinCalcFrameRect(hwnd
, &rcl
, TRUE
);
368 if (rcl
.xRight
- rcl
.xLeft
<= SRC_WIDTH
)
369 rcl
.xRight
= rcl
.xLeft
+ (SRC_WIDTH
+ 1);
371 if (rcl
.yTop
- rcl
.yBottom
<= SRC_HEIGHT
)
372 rcl
.yTop
= rcl
.yBottom
+ (SRC_HEIGHT
+ 1);
374 WinCalcFrameRect(hwnd
, &rcl
, FALSE
);
376 if (rcl
.xRight
- rcl
.xLeft
> vo_screenwidth
) {
378 rcl
.xRight
= vo_screenwidth
;
381 if (rcl
.yTop
- rcl
.yBottom
> vo_screenheight
) {
383 rcl
.yTop
= vo_screenheight
;
386 pswp
->fl
|= SWP_MOVE
;
388 pswp
->y
= rcl
.yBottom
;
389 pswp
->cx
= rcl
.xRight
- rcl
.xLeft
;
390 pswp
->cy
= rcl
.yTop
- rcl
.yBottom
;
396 return m_int
.pfnwpOldFrame(hwnd
, msg
, mp1
, mp2
);
399 static MRESULT EXPENTRY
WndProc(HWND hwnd
, ULONG msg
, MPARAM mp1
, MPARAM mp2
)
401 // if slave mode, ignore mouse events and deliver them to a parent window
403 ((msg
>= WM_MOUSEFIRST
&& msg
<= WM_MOUSELAST
) ||
404 (msg
>= WM_EXTMOUSEFIRST
&& msg
<= WM_EXTMOUSELAST
))) {
405 WinPostMsg(HWNDFROMWINID(WinID
), msg
, mp1
, mp2
);
407 return (MRESULT
)TRUE
;
412 mplayer_put_key(KEY_CLOSE_WIN
);
418 USHORT fsFlags
= SHORT1FROMMP(mp1
);
419 UCHAR uchScan
= CHAR4FROMMP(mp1
);
420 USHORT usCh
= SHORT1FROMMP(mp2
);
421 USHORT usVk
= SHORT2FROMMP(mp2
);
424 if (fsFlags
& KC_KEYUP
)
427 if (fsFlags
& KC_SCANCODE
) {
428 mpkey
= lookup_keymap_table(m_keypad_map
, uchScan
);
430 // distinguish KEY_KP0 and KEY_KPINS
431 if (mpkey
== KEY_KP0
&& usCh
!= '0')
434 // distinguish KEY_KPDEC and KEY_KPDEL
435 if (mpkey
== KEY_KPDEC
&& usCh
!= '.')
438 mplayer_put_key(mpkey
);
440 return (MRESULT
)TRUE
;
444 if (fsFlags
& KC_VIRTUALKEY
) {
445 mpkey
= lookup_keymap_table(m_vk_map
, usVk
);
447 mplayer_put_key(mpkey
);
449 return (MRESULT
)TRUE
;
453 if ((fsFlags
& KC_CHAR
) && !HIBYTE(usCh
))
454 mplayer_put_key(usCh
);
456 return (MRESULT
)TRUE
;
462 case WM_BUTTON1DBLCLK
:
463 case WM_BUTTON3DBLCLK
:
464 case WM_BUTTON2DBLCLK
:
465 if (WinQueryFocus(HWND_DESKTOP
) != hwnd
)
466 WinSetFocus(HWND_DESKTOP
, hwnd
);
467 else if (!vo_nomouse_input
)
468 mplayer_put_key(lookup_keymap_table(m_mouse_map
, msg
));
470 return (MRESULT
)TRUE
;
480 // get a current movie area
481 kvaAdjustDstRect(&m_int
.kvas
.rclSrcRect
, &rclDst
);
483 // get a current invalidated area
484 hps
= WinBeginPaint(hwnd
, NULLHANDLE
, &rcl
);
486 // create a region for an invalidated area
487 hrgn
= GpiCreateRegion(hps
, 1, &rcl
);
488 // create a region for a movie area
489 hrgnDst
= GpiCreateRegion(hps
, 1, &rclDst
);
491 // exclude a movie area from an invalidated area
492 GpiCombineRegion(hps
, hrgn
, hrgn
, hrgnDst
, CRGN_DIFF
);
494 // get rectangles from the region
496 rgnCtl
.ulDirection
= RECTDIR_LFRT_TOPBOT
;
497 GpiQueryRegionRects(hps
, hrgn
, NULL
, &rgnCtl
, NULL
);
499 if (rgnCtl
.crcReturned
> 0) {
500 rgnCtl
.crc
= rgnCtl
.crcReturned
;
501 prcl
= malloc(sizeof(RECTL
) * rgnCtl
.crcReturned
);
504 // draw black bar if needed
505 if (prcl
&& GpiQueryRegionRects(hps
, hrgn
, NULL
, &rgnCtl
, prcl
)) {
508 for (i
= 0; i
< rgnCtl
.crcReturned
; i
++)
509 WinFillRect(hps
, &prcl
[i
], CLR_BLACK
);
514 GpiDestroyRegion(hps
, hrgnDst
);
515 GpiDestroyRegion(hps
, hrgn
);
523 return WinDefWindowProc(hwnd
, msg
, mp1
, mp2
);
526 // Change process type from VIO to PM to use PM APIs.
527 static void morphToPM(void)
531 DosGetInfoBlocks(NULL
, &pib
);
533 // Change flag from VIO to PM:
534 if (pib
->pib_ultype
== 2)
538 static int preinit(const char *arg
)
549 const opt_t subopts
[] = {
550 {"snap", OPT_ARG_BOOL
, &fUseSnap
, NULL
},
551 {"wo", OPT_ARG_BOOL
, &fUseWO
, NULL
},
552 {"dive", OPT_ARG_BOOL
, &fUseDive
, NULL
},
553 {"t23", OPT_ARG_BOOL
, &fFixT23
, NULL
},
554 {NULL
, 0, NULL
, NULL
}
557 PCSZ pcszVideoModeStr
[3] = {"DIVE", "WarpOverlay!", "SNAP"};
559 if (subopt_parse(arg
, subopts
) != 0)
564 memset(&m_int
, 0, sizeof(m_int
));
566 m_int
.hab
= WinInitialize(0);
567 m_int
.hmq
= WinCreateMsgQueue(m_int
.hab
, 0);
569 WinRegisterClass(m_int
.hab
,
572 CS_SIZEREDRAW
| CS_MOVENOTIFY
,
576 hwndParent
= HWND_DESKTOP
;
577 flFrameFlags
= FCF_SYSMENU
| FCF_TITLEBAR
| FCF_MINMAX
|
578 FCF_SIZEBORDER
| FCF_TASKLIST
;
582 hwndParent
= HWNDFROMWINID(WinID
);
585 // Prevent a parent window from painting over our window
586 ulStyle
= WinQueryWindowULong(hwndParent
, QWL_STYLE
);
587 WinSetWindowULong(hwndParent
, QWL_STYLE
, ulStyle
| WS_CLIPCHILDREN
);
591 WinCreateStdWindow(hwndParent
, // parent window handle
592 WS_VISIBLE
, // frame window style
593 &flFrameFlags
, // window style
594 WC_MPLAYER
, // class name
596 0L, // default client style
597 NULLHANDLE
, // resource in exe file
598 1, // frame window id
599 &m_int
.hwndClient
); // client window handle
601 if (m_int
.hwndFrame
== NULLHANDLE
)
604 m_int
.hwndSysMenu
= WinWindowFromID(m_int
.hwndFrame
, FID_SYSMENU
);
605 m_int
.hwndTitleBar
= WinWindowFromID(m_int
.hwndFrame
, FID_TITLEBAR
);
606 m_int
.hwndMinMax
= WinWindowFromID(m_int
.hwndFrame
, FID_MINMAX
);
608 m_int
.fFixT23
= fFixT23
;
611 m_int
.pfnwpOldFrame
= WinSubclassWindow(m_int
.hwndFrame
,
614 if (!!fUseSnap
+ !!fUseWO
+ !!fUseDive
> 1)
615 mp_msg(MSGT_VO
, MSGL_WARN
,"KVA: Multiple mode specified!!!\n");
626 if (kvaInit(kvaMode
, m_int
.hwndClient
, vo_colorkey
)) {
627 mp_msg(MSGT_VO
, MSGL_ERR
, "KVA: Init failed!!!\n");
632 kvaCaps(&m_int
.kvac
);
634 mp_msg(MSGT_VO
, MSGL_V
, "KVA: Selected video mode = %s\n",
635 pcszVideoModeStr
[m_int
.kvac
.ulMode
- 1]);
637 kvaDisableScreenSaver();
639 // Might cause PM DLLs to be loaded which incorrectly enable SIG_FPE,
640 // so mask off all floating-point exceptions.
641 _control87(MCW_EM
, MCW_EM
);
646 static void uninit(void)
648 kvaEnableScreenSaver();
652 sws_freeContext(m_int
.sws
);
654 if (m_int
.hwndFrame
!= NULLHANDLE
) {
659 WinSubclassWindow(m_int
.hwndFrame
, m_int
.pfnwpOldFrame
);
661 WinDestroyWindow(m_int
.hwndFrame
);
664 WinDestroyMsgQueue(m_int
.hmq
);
665 WinTerminate(m_int
.hab
);
668 static int config(uint32_t width
, uint32_t height
,
669 uint32_t d_width
, uint32_t d_height
,
670 uint32_t flags
, char *title
, uint32_t format
)
674 mp_msg(MSGT_VO
, MSGL_V
,
675 "KVA: Using 0x%X (%s) image format, vo_config_count = %d\n",
676 format
, vo_format_name(format
), vo_config_count
);
680 if (query_format_info(format
, &m_int
.fHWAccel
, &m_int
.fcc
, &m_int
.bpp
,
681 &m_int
.nChromaShift
))
684 m_int
.iImageFormat
= format
;
686 // if there is no hw accel for given format,
687 // try any format supported by hw accel
688 if (!m_int
.fHWAccel
) {
691 sws_freeContext(m_int
.sws
);
693 if (m_int
.kvac
.ulInputFormatFlags
& KVAF_YV12
)
694 dstFormat
= IMGFMT_YV12
;
695 else if (m_int
.kvac
.ulInputFormatFlags
& KVAF_YUY2
)
696 dstFormat
= IMGFMT_YUY2
;
697 else if (m_int
.kvac
.ulInputFormatFlags
& KVAF_YVU9
)
698 dstFormat
= IMGFMT_YVU9
;
699 else if (m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR24
)
700 dstFormat
= IMGFMT_BGR24
;
701 else if (m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR16
)
702 dstFormat
= IMGFMT_BGR16
;
703 else if (m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR15
)
704 dstFormat
= IMGFMT_BGR15
;
706 if (query_format_info(dstFormat
, NULL
, &m_int
.fcc
, NULL
, NULL
))
709 m_int
.sws
= sws_getContextFromCmdLine(width
, height
, format
,
710 width
, height
, dstFormat
);
713 mp_msg(MSGT_VO
, MSGL_V
, "KVA: Selected FOURCC = %.4s\n", (char *)&m_int
.fcc
);
715 m_int
.kvas
.ulLength
= sizeof(KVASETUP
);
716 m_int
.kvas
.szlSrcSize
.cx
= width
;
717 m_int
.kvas
.szlSrcSize
.cy
= height
;
718 m_int
.kvas
.rclSrcRect
.xLeft
= 0;
719 m_int
.kvas
.rclSrcRect
.yTop
= 0;
720 m_int
.kvas
.rclSrcRect
.xRight
= width
;
721 m_int
.kvas
.rclSrcRect
.yBottom
= height
;
722 m_int
.kvas
.ulRatio
= vo_keepaspect
? KVAR_FORCEANY
: KVAR_NONE
;
723 m_int
.kvas
.ulAspectWidth
= d_width
;
724 m_int
.kvas
.ulAspectHeight
= d_height
;
725 m_int
.kvas
.fccSrcColor
= m_int
.fcc
;
726 m_int
.kvas
.fDither
= TRUE
;
728 if (kvaSetup(&m_int
.kvas
)) {
729 mp_msg(MSGT_VO
, MSGL_ERR
, "KVA: Setup failed!!!\n");
734 m_int
.lStride
= width
* m_int
.bpp
;
739 WinSetWindowText(m_int
.hwndFrame
, title
);
741 // initialize 'vo_fs' only once at first config() call
742 if (vo_config_count
== 0)
743 vo_fs
= flags
& VOFLAG_FULLSCREEN
;
745 // workaround for T23 laptop with S3 Video by Franz Bakan
746 if (!vo_fs
&& m_int
.fFixT23
) {
751 m_int
.rclDst
.xLeft
= ((LONG
)vo_screenwidth
- (LONG
)d_width
) / 2;
752 m_int
.rclDst
.yBottom
= ((LONG
)vo_screenheight
- (LONG
)d_height
) / 2;
753 m_int
.rclDst
.xRight
= m_int
.rclDst
.xLeft
+ d_width
;
754 m_int
.rclDst
.yTop
= m_int
.rclDst
.yBottom
+ d_height
;
757 d_width
= vo_screenwidth
;
758 d_height
= vo_screenheight
;
760 // when -fs option is used without this, title bar is not highlighted
761 WinSetActiveWindow(HWND_DESKTOP
, m_int
.hwndFrame
);
763 WinSetParent(m_int
.hwndSysMenu
, HWND_OBJECT
, FALSE
);
764 WinSetParent(m_int
.hwndTitleBar
, HWND_OBJECT
, FALSE
);
765 WinSetParent(m_int
.hwndMinMax
, HWND_OBJECT
, FALSE
);
767 setAspectRatio(KVAR_FORCEANY
);
770 rcl
.xLeft
= ((LONG
)vo_screenwidth
- (LONG
)d_width
) / 2;
771 rcl
.yBottom
= ((LONG
)vo_screenheight
- (LONG
)d_height
) /2 ;
772 rcl
.xRight
= rcl
.xLeft
+ d_width
;
773 rcl
.yTop
= rcl
.yBottom
+ d_height
;
777 WinQueryWindowRect(HWNDFROMWINID(WinID
), &m_int
.rclDst
);
781 WinCalcFrameRect(m_int
.hwndFrame
, &rcl
, FALSE
);
783 WinSetWindowPos(m_int
.hwndFrame
, HWND_TOP
,
784 rcl
.xLeft
, rcl
.yBottom
,
785 rcl
.xRight
- rcl
.xLeft
, rcl
.yTop
- rcl
.yBottom
,
786 SWP_SIZE
| SWP_MOVE
| SWP_ZORDER
| SWP_SHOW
|
787 (WinID
== -1 ? SWP_ACTIVATE
: 0));
789 WinInvalidateRect(m_int
.hwndFrame
, NULL
, TRUE
);
794 static uint32_t get_image(mp_image_t
*mpi
)
796 if (m_int
.iImageFormat
!= mpi
->imgfmt
)
799 if (mpi
->type
== MP_IMGTYPE_STATIC
|| mpi
->type
== MP_IMGTYPE_TEMP
) {
800 if (mpi
->flags
& MP_IMGFLAG_PLANAR
) {
801 mpi
->planes
[1] = m_int
.planes
[1];
802 mpi
->planes
[2] = m_int
.planes
[2];
804 mpi
->stride
[1] = m_int
.stride
[1];
805 mpi
->stride
[2] = m_int
.stride
[2];
808 mpi
->planes
[0] = m_int
.planes
[0];
809 mpi
->stride
[0] = m_int
.stride
[0];
810 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
818 static uint32_t draw_image(mp_image_t
*mpi
)
820 // if -dr or -slices then do nothing:
821 if (mpi
->flags
& (MP_IMGFLAG_DIRECT
| MP_IMGFLAG_DRAW_CALLBACK
))
824 draw_slice(mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, mpi
->x
, mpi
->y
);
829 static int query_format(uint32_t format
)
834 if (query_format_info(format
, &fHWAccel
, NULL
, NULL
, NULL
))
837 res
= VFCAP_CSP_SUPPORTED
| VFCAP_OSD
;
839 res
|= VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_HWSCALE_UP
;
842 res
|= VFCAP_HWSCALE_DOWN
;
848 static int fs_toggle(void)
857 WinQueryWindowPos(m_int
.hwndFrame
, &swp
);
858 m_int
.rclDst
.xLeft
= swp
.x
;
859 m_int
.rclDst
.yBottom
= swp
.y
;
860 m_int
.rclDst
.xRight
= m_int
.rclDst
.xLeft
+ swp
.cx
;
861 m_int
.rclDst
.yTop
= m_int
.rclDst
.yBottom
+ swp
.cy
;
862 WinCalcFrameRect(m_int
.hwndFrame
, &m_int
.rclDst
, TRUE
);
865 WinSetParent(m_int
.hwndFrame
, HWND_DESKTOP
, FALSE
);
867 WinSetParent(m_int
.hwndSysMenu
, HWND_OBJECT
, FALSE
);
868 WinSetParent(m_int
.hwndTitleBar
, HWND_OBJECT
, FALSE
);
869 WinSetParent(m_int
.hwndMinMax
, HWND_OBJECT
, FALSE
);
873 rcl
.xRight
= vo_screenwidth
;
874 rcl
.yTop
= vo_screenheight
;
876 setAspectRatio(KVAR_FORCEANY
);
879 WinSetParent(m_int
.hwndFrame
, HWNDFROMWINID(WinID
), TRUE
);
881 WinSetParent(m_int
.hwndSysMenu
, m_int
.hwndFrame
, FALSE
);
882 WinSetParent(m_int
.hwndTitleBar
, m_int
.hwndFrame
, FALSE
);
883 WinSetParent(m_int
.hwndMinMax
, m_int
.hwndFrame
, FALSE
);
887 setAspectRatio(vo_keepaspect
? KVAR_FORCEANY
: KVAR_NONE
);
890 WinCalcFrameRect(m_int
.hwndFrame
, &rcl
, FALSE
);
892 WinSetWindowPos(m_int
.hwndFrame
, HWND_TOP
,
893 rcl
.xLeft
, rcl
.yBottom
,
894 rcl
.xRight
- rcl
.xLeft
, rcl
.yTop
- rcl
.yBottom
,
895 SWP_SIZE
| SWP_MOVE
| SWP_ZORDER
| SWP_SHOW
|
896 (WinID
== -1 ? SWP_ACTIVATE
: 0));
901 static int color_ctrl_set(char *what
, int value
)
906 if (!strcmp(what
, "brightness"))
907 ulAttr
= KVAA_BRIGHTNESS
;
908 else if (!strcmp(what
, "contrast"))
909 ulAttr
= KVAA_CONTRAST
;
910 else if (!strcmp(what
, "hue"))
912 else if (!strcmp(what
, "saturation"))
913 ulAttr
= KVAA_SATURATION
;
917 ulValue
= (value
+ 100) * 255 / 200;
919 if (kvaSetAttr(ulAttr
, &ulValue
))
925 static int color_ctrl_get(char *what
, int *value
)
930 if (!strcmp(what
, "brightness"))
931 ulAttr
= KVAA_BRIGHTNESS
;
932 else if (!strcmp(what
, "contrast"))
933 ulAttr
= KVAA_CONTRAST
;
934 else if (!strcmp(what
, "hue"))
936 else if (!strcmp(what
, "saturation"))
937 ulAttr
= KVAA_SATURATION
;
941 if (kvaQueryAttr(ulAttr
, &ulValue
))
944 // add 1 to adjust range
945 *value
= ((ulValue
+ 1) * 200 / 255) - 100;
950 static int control(uint32_t request
, void *data
)
953 case VOCTRL_GET_IMAGE
:
954 return get_image(data
);
956 case VOCTRL_DRAW_IMAGE
:
957 return draw_image(data
);
959 case VOCTRL_QUERY_FORMAT
:
960 return query_format(*(uint32_t *)data
);
962 case VOCTRL_FULLSCREEN
:
965 case VOCTRL_SET_EQUALIZER
:
967 struct voctrl_set_equalizer_args
*args
= data
;
968 color_ctrl_set(args
->name
, args
->value
);
971 case VOCTRL_GET_EQUALIZER
:
973 struct voctrl_get_equalizer_args
*args
= data
;
974 return color_ctrl_get(args
->name
, args
->valueptr
);
977 case VOCTRL_UPDATE_SCREENINFO
:
978 vo_screenwidth
= m_int
.kvac
.cxScreen
;
979 vo_screenheight
= m_int
.kvac
.cyScreen
;
981 aspect_save_screenres(vo_screenwidth
, vo_screenheight
);
989 static int draw_frame(uint8_t *src
[])
994 static int draw_slice(uint8_t *src
[], int stride
[], int w
, int h
, int x
, int y
)
1000 d
= m_int
.planes
[0] + m_int
.stride
[0] * y
+ x
;
1002 mem2agpcpy_pic(d
, s
, w
* m_int
.bpp
, h
, m_int
.stride
[0], stride
[0]);
1005 if (m_int
.nChromaShift
) {
1006 w
>>= m_int
.nChromaShift
; h
>>= m_int
.nChromaShift
;
1007 x
>>= m_int
.nChromaShift
; y
>>= m_int
.nChromaShift
;
1010 d
= m_int
.planes
[1] + m_int
.stride
[1] * y
+ x
;
1012 mem2agpcpy_pic(d
, s
, w
, h
, m_int
.stride
[1], stride
[1]);
1015 d
= m_int
.planes
[2] + m_int
.stride
[2] * y
+ x
;
1017 mem2agpcpy_pic(d
, s
, w
, h
, m_int
.stride
[2], stride
[2]);
1023 #define vo_draw_alpha(imgfmt) \
1024 vo_draw_alpha_##imgfmt(w, h, src, srca, stride, \
1025 m_int.planes[0] + m_int.stride[0] * y0 + m_int.bpp * x0, \
1028 static void draw_alpha(int x0
, int y0
, int w
, int h
,
1029 unsigned char *src
, unsigned char *srca
, int stride
)
1031 switch (m_int
.iImageFormat
) {
1034 vo_draw_alpha(yv12
);
1038 vo_draw_alpha(yuy2
);
1042 vo_draw_alpha(rgb24
);
1046 vo_draw_alpha(rgb16
);
1050 vo_draw_alpha(rgb15
);
1055 static void draw_osd(void)
1057 vo_draw_text(SRC_WIDTH
, SRC_HEIGHT
, draw_alpha
);
1060 static void flip_page(void)
1065 static void check_events(void)
1069 // On slave mode, we need to change our window size according to a
1070 // parent window size
1074 WinQueryWindowRect(HWNDFROMWINID(WinID
), &rcl
);
1076 if (rcl
.xLeft
!= m_int
.rclParent
.xLeft
||
1077 rcl
.yBottom
!= m_int
.rclParent
.yBottom
||
1078 rcl
.xRight
!= m_int
.rclParent
.xRight
||
1079 rcl
.yTop
!= m_int
.rclParent
.yTop
) {
1080 WinSetWindowPos(m_int
.hwndFrame
, NULLHANDLE
,
1081 rcl
.xLeft
, rcl
.yBottom
,
1082 rcl
.xRight
- rcl
.xLeft
, rcl
.yTop
- rcl
.yBottom
,
1083 SWP_SIZE
| SWP_MOVE
);
1085 m_int
.rclParent
= rcl
;
1089 while (WinPeekMsg(m_int
.hab
, &qm
, NULLHANDLE
, 0, 0, PM_REMOVE
))
1090 WinDispatchMsg(m_int
.hab
, &qm
);