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.
41 #include "video_out.h"
42 #include "video_out_internal.h"
45 #include "fastmemcpy.h"
47 #include "osdep/keycodes.h"
48 #include "input/input.h"
49 #include "input/mouse.h"
50 #include "subopt-helper.h"
53 #include "cpudetect.h"
54 #include "libswscale/swscale.h"
55 #include "libmpcodecs/vf_scale.h"
57 static const vo_info_t info
= {
58 "SNAP/WarpOverlay!/DIVE video output",
60 "KO Myung-Hun <komh@chollian.net>",
66 #define WC_MPLAYER "WC_MPLAYER"
68 #define SRC_WIDTH m_int.kvas.szlSrcSize.cx
69 #define SRC_HEIGHT m_int.kvas.szlSrcSize.cy
71 #define HWNDFROMWINID(wid) ((wid) + 0x80000000UL)
73 static const struct keymap m_vk_map
[] = {
74 {VK_NEWLINE
, KEY_ENTER
}, {VK_TAB
, KEY_TAB
}, {VK_SPACE
, ' '},
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
},
84 {VK_RIGHT
, KEY_RIGHT
}, {VK_LEFT
, KEY_LEFT
},
85 {VK_DOWN
, KEY_DOWN
}, {VK_UP
, KEY_UP
},
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},
95 static const struct keymap m_keypad_map
[] = {
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
},
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
},
134 uint8_t *planes
[3]; // y = 0, u = 1, v = 2
138 struct SwsContext
*sws
;
141 static inline void setAspectRatio(ULONG ulRatio
)
143 m_int
.kvas
.ulRatio
= ulRatio
;
144 kvaSetup(&m_int
.kvas
);
147 static int query_format_info(int format
, PBOOL pfHWAccel
, PFOURCC pfcc
,
148 int *pbpp
, int *pnChromaShift
)
157 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YV12
;
164 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YUY2
;
171 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YVU9
;
178 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR24
;
185 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR16
;
192 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR15
;
203 *pfHWAccel
= fHWAccel
;
212 *pnChromaShift
= nChromaShift
;
217 static void imgCreate(void)
219 int size
= SRC_HEIGHT
* m_int
.lStride
;;
221 switch (m_int
.iImageFormat
) {
231 m_int
.pbImage
= malloc(size
);
233 m_int
.planes
[0] = m_int
.pbImage
;
234 m_int
.stride
[0] = m_int
.lStride
;
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
;
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];
247 static void imgFree(void)
251 m_int
.pbImage
= NULL
;
254 static void imgDisplay(void)
259 if (!kvaLockBuffer(&pBuffer
, &ulBPL
)) {
265 dstStride
[0] = ulBPL
;
268 if (m_int
.nChromaShift
) {
270 dst
[2] = dst
[0] + SRC_HEIGHT
* dstStride
[0];
271 dstStride
[2] = dstStride
[0] >> m_int
.nChromaShift
;
275 (SRC_HEIGHT
>> m_int
.nChromaShift
) * dstStride
[2];
276 dstStride
[1] = dstStride
[2];
279 if (m_int
.fHWAccel
) {
286 mem2agpcpy_pic(dst
[0], m_int
.planes
[0], w
, h
,
287 dstStride
[0], m_int
.stride
[0]);
290 if (m_int
.nChromaShift
) {
291 w
>>= m_int
.nChromaShift
; h
>>= m_int
.nChromaShift
;
294 mem2agpcpy_pic(dst
[1], m_int
.planes
[1], w
, h
,
295 dstStride
[1], m_int
.stride
[1]);
298 mem2agpcpy_pic(dst
[2], m_int
.planes
[2], w
, h
,
299 dstStride
[2], m_int
.stride
[2]);
302 sws_scale(m_int
.sws
, m_int
.planes
, m_int
.stride
, 0, SRC_HEIGHT
,
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
,
316 case WM_QUERYTRACKINFO
:
318 PTRACKINFO pti
= (PTRACKINFO
)mp2
;
324 m_int
.pfnwpOldFrame(hwnd
, msg
, mp1
, mp2
);
328 rcl
.xRight
= SRC_WIDTH
+ 1;
329 rcl
.yTop
= SRC_HEIGHT
+ 1;
331 WinCalcFrameRect(hwnd
, &rcl
, FALSE
);
333 pti
->ptlMinTrackSize
.x
= rcl
.xRight
- rcl
.xLeft
;
334 pti
->ptlMinTrackSize
.y
= rcl
.yTop
- rcl
.yBottom
;
336 pti
->ptlMaxTrackSize
.x
= vo_screenwidth
;
337 pti
->ptlMaxTrackSize
.y
= vo_screenheight
;
339 return (MRESULT
)TRUE
;
342 case WM_ADJUSTWINDOWPOS
:
344 PSWP pswp
= (PSWP
)mp1
;
350 if (pswp
->fl
& SWP_SIZE
) {
352 rcl
.yBottom
= pswp
->y
;
353 rcl
.xRight
= rcl
.xLeft
+ pswp
->cx
;
354 rcl
.yTop
= rcl
.yBottom
+ pswp
->cy
;
356 WinCalcFrameRect(hwnd
, &rcl
, TRUE
);
358 if (rcl
.xRight
- rcl
.xLeft
<= SRC_WIDTH
)
359 rcl
.xRight
= rcl
.xLeft
+ (SRC_WIDTH
+ 1);
361 if (rcl
.yTop
- rcl
.yBottom
<= SRC_HEIGHT
)
362 rcl
.yTop
= rcl
.yBottom
+ (SRC_HEIGHT
+ 1);
364 WinCalcFrameRect(hwnd
, &rcl
, FALSE
);
366 if (rcl
.xRight
- rcl
.xLeft
> vo_screenwidth
) {
368 rcl
.xRight
= vo_screenwidth
;
371 if (rcl
.yTop
- rcl
.yBottom
> vo_screenheight
) {
373 rcl
.yTop
= vo_screenheight
;
376 pswp
->fl
|= SWP_MOVE
;
378 pswp
->y
= rcl
.yBottom
;
379 pswp
->cx
= rcl
.xRight
- rcl
.xLeft
;
380 pswp
->cy
= rcl
.yTop
- rcl
.yBottom
;
386 return m_int
.pfnwpOldFrame(hwnd
, msg
, mp1
, mp2
);
389 static MRESULT EXPENTRY
WndProc(HWND hwnd
, ULONG msg
, MPARAM mp1
, MPARAM mp2
)
391 // if slave mode, ignore mouse events and deliver them to a parent window
393 ((msg
>= WM_MOUSEFIRST
&& msg
<= WM_MOUSELAST
) ||
394 (msg
>= WM_EXTMOUSEFIRST
&& msg
<= WM_EXTMOUSELAST
))) {
395 WinPostMsg(HWNDFROMWINID(WinID
), msg
, mp1
, mp2
);
397 return (MRESULT
)TRUE
;
402 mplayer_put_key(KEY_CLOSE_WIN
);
408 USHORT fsFlags
= SHORT1FROMMP(mp1
);
409 UCHAR uchScan
= CHAR4FROMMP(mp1
);
410 USHORT usCh
= SHORT1FROMMP(mp2
);
411 USHORT usVk
= SHORT2FROMMP(mp2
);
414 if (fsFlags
& KC_KEYUP
)
417 if (fsFlags
& KC_SCANCODE
) {
418 mpkey
= lookup_keymap_table(m_keypad_map
, uchScan
);
420 // distinguish KEY_KP0 and KEY_KPINS
421 if (mpkey
== KEY_KP0
&& usCh
!= '0')
424 // distinguish KEY_KPDEC and KEY_KPDEL
425 if (mpkey
== KEY_KPDEC
&& usCh
!= '.')
428 mplayer_put_key(mpkey
);
430 return (MRESULT
)TRUE
;
434 if (fsFlags
& KC_VIRTUALKEY
) {
435 mpkey
= lookup_keymap_table(m_vk_map
, usVk
);
437 mplayer_put_key(mpkey
);
439 return (MRESULT
)TRUE
;
443 if ((fsFlags
& KC_CHAR
) && !HIBYTE(usCh
))
444 mplayer_put_key(usCh
);
446 return (MRESULT
)TRUE
;
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
));
460 return (MRESULT
)TRUE
;
470 // get a current movie area
471 kvaAdjustDstRect(&m_int
.kvas
.rclSrcRect
, &rclDst
);
473 // get a current invalidated area
474 hps
= WinBeginPaint(hwnd
, NULLHANDLE
, &rcl
);
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
);
481 // exclude a movie area from an invalidated area
482 GpiCombineRegion(hps
, hrgn
, hrgn
, hrgnDst
, CRGN_DIFF
);
484 // get rectangles from the region
486 rgnCtl
.ulDirection
= RECTDIR_LFRT_TOPBOT
;
487 GpiQueryRegionRects(hps
, hrgn
, NULL
, &rgnCtl
, NULL
);
489 if (rgnCtl
.crcReturned
> 0) {
490 rgnCtl
.crc
= rgnCtl
.crcReturned
;
491 prcl
= malloc(sizeof(RECTL
) * rgnCtl
.crcReturned
);
494 // draw black bar if needed
495 if (prcl
&& GpiQueryRegionRects(hps
, hrgn
, NULL
, &rgnCtl
, prcl
)) {
498 for (i
= 0; i
< rgnCtl
.crcReturned
; i
++)
499 WinFillRect(hps
, &prcl
[i
], CLR_BLACK
);
504 GpiDestroyRegion(hps
, hrgnDst
);
505 GpiDestroyRegion(hps
, hrgn
);
513 return WinDefWindowProc(hwnd
, msg
, mp1
, mp2
);
516 // Change process type from VIO to PM to use PM APIs.
517 static void morphToPM(void)
521 DosGetInfoBlocks(NULL
, &pib
);
523 // Change flag from VIO to PM:
524 if (pib
->pib_ultype
== 2)
528 static int preinit(const char *arg
)
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
}
547 PCSZ pcszVideoModeStr
[3] = {"DIVE", "WarpOverlay!", "SNAP"};
549 if (subopt_parse(arg
, subopts
) != 0)
554 memset(&m_int
, 0, sizeof(m_int
));
556 m_int
.hab
= WinInitialize(0);
557 m_int
.hmq
= WinCreateMsgQueue(m_int
.hab
, 0);
559 WinRegisterClass(m_int
.hab
,
562 CS_SIZEREDRAW
| CS_MOVENOTIFY
,
566 hwndParent
= HWND_DESKTOP
;
567 flFrameFlags
= FCF_SYSMENU
| FCF_TITLEBAR
| FCF_MINMAX
|
568 FCF_SIZEBORDER
| FCF_TASKLIST
;
570 hwndParent
= HWNDFROMWINID(WinID
);
575 WinCreateStdWindow(hwndParent
, // parent window handle
576 WS_VISIBLE
, // frame window style
577 &flFrameFlags
, // window style
578 WC_MPLAYER
, // class name
580 0L, // default client style
581 NULLHANDLE
, // resource in exe file
582 1, // frame window id
583 &m_int
.hwndClient
); // client window handle
585 if (m_int
.hwndFrame
== NULLHANDLE
)
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
);
592 m_int
.fFixT23
= fFixT23
;
595 m_int
.pfnwpOldFrame
= WinSubclassWindow(m_int
.hwndFrame
,
598 if (!!fUseSnap
+ !!fUseWO
+ !!fUseDive
> 1)
599 mp_msg(MSGT_VO
, MSGL_WARN
,"KVA: Multiple mode specified!!!\n");
610 if (kvaInit(kvaMode
, m_int
.hwndClient
, vo_colorkey
)) {
611 mp_msg(MSGT_VO
, MSGL_ERR
, "KVA: Init failed!!!\n");
616 kvaCaps(&m_int
.kvac
);
618 mp_msg(MSGT_VO
, MSGL_V
, "KVA: Selected video mode = %s\n",
619 pcszVideoModeStr
[m_int
.kvac
.ulMode
- 1]);
621 kvaDisableScreenSaver();
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
);
630 static void uninit(void)
632 kvaEnableScreenSaver();
636 sws_freeContext(m_int
.sws
);
638 if (m_int
.hwndFrame
!= NULLHANDLE
) {
643 WinSubclassWindow(m_int
.hwndFrame
, m_int
.pfnwpOldFrame
);
645 WinDestroyWindow(m_int
.hwndFrame
);
648 WinDestroyMsgQueue(m_int
.hmq
);
649 WinTerminate(m_int
.hab
);
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
)
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
);
664 if (query_format_info(format
, &m_int
.fHWAccel
, &m_int
.fcc
, &m_int
.bpp
,
665 &m_int
.nChromaShift
))
668 m_int
.iImageFormat
= format
;
670 // if there is no hw accel for given format,
671 // try any format supported by hw accel
672 if (!m_int
.fHWAccel
) {
675 sws_freeContext(m_int
.sws
);
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
;
690 if (query_format_info(dstFormat
, NULL
, &m_int
.fcc
, NULL
, NULL
))
693 m_int
.sws
= sws_getContextFromCmdLine(width
, height
, format
,
694 width
, height
, dstFormat
);
697 mp_msg(MSGT_VO
, MSGL_V
, "KVA: Selected FOURCC = %.4s\n", (char *)&m_int
.fcc
);
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
;
712 if (kvaSetup(&m_int
.kvas
)) {
713 mp_msg(MSGT_VO
, MSGL_ERR
, "KVA: Setup failed!!!\n");
718 m_int
.lStride
= width
* m_int
.bpp
;
723 WinSetWindowText(m_int
.hwndFrame
, title
);
725 // initialize 'vo_fs' only once at first config() call
726 if (vo_config_count
== 0)
727 vo_fs
= flags
& VOFLAG_FULLSCREEN
;
729 // workaround for T23 laptop with S3 Video by Franz Bakan
730 if (!vo_fs
&& m_int
.fFixT23
) {
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
;
741 d_width
= vo_screenwidth
;
742 d_height
= vo_screenheight
;
744 // when -fs option is used without this, title bar is not highlighted
745 WinSetActiveWindow(HWND_DESKTOP
, m_int
.hwndFrame
);
747 WinSetParent(m_int
.hwndSysMenu
, HWND_OBJECT
, FALSE
);
748 WinSetParent(m_int
.hwndTitleBar
, HWND_OBJECT
, FALSE
);
749 WinSetParent(m_int
.hwndMinMax
, HWND_OBJECT
, FALSE
);
751 setAspectRatio(KVAR_FORCEANY
);
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
;
761 WinQueryWindowRect(HWNDFROMWINID(WinID
), &m_int
.rclDst
);
765 WinCalcFrameRect(m_int
.hwndFrame
, &rcl
, FALSE
);
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));
773 WinInvalidateRect(m_int
.hwndFrame
, NULL
, TRUE
);
778 static uint32_t get_image(mp_image_t
*mpi
)
780 if (m_int
.iImageFormat
!= mpi
->imgfmt
)
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];
788 mpi
->stride
[1] = m_int
.stride
[1];
789 mpi
->stride
[2] = m_int
.stride
[2];
792 mpi
->planes
[0] = m_int
.planes
[0];
793 mpi
->stride
[0] = m_int
.stride
[0];
794 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
802 static uint32_t draw_image(mp_image_t
*mpi
)
804 // if -dr or -slices then do nothing:
805 if (mpi
->flags
& (MP_IMGFLAG_DIRECT
| MP_IMGFLAG_DRAW_CALLBACK
))
808 draw_slice(mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, mpi
->x
, mpi
->y
);
813 static int query_format(uint32_t format
)
818 if (query_format_info(format
, &fHWAccel
, NULL
, NULL
, NULL
))
821 res
= VFCAP_CSP_SUPPORTED
| VFCAP_OSD
;
823 res
|= VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_HWSCALE_UP
;
826 res
|= VFCAP_HWSCALE_DOWN
;
832 static int fs_toggle(void)
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
);
849 WinSetParent(m_int
.hwndFrame
, HWND_DESKTOP
, FALSE
);
851 WinSetParent(m_int
.hwndSysMenu
, HWND_OBJECT
, FALSE
);
852 WinSetParent(m_int
.hwndTitleBar
, HWND_OBJECT
, FALSE
);
853 WinSetParent(m_int
.hwndMinMax
, HWND_OBJECT
, FALSE
);
857 rcl
.xRight
= vo_screenwidth
;
858 rcl
.yTop
= vo_screenheight
;
860 setAspectRatio(KVAR_FORCEANY
);
863 WinSetParent(m_int
.hwndFrame
, HWNDFROMWINID(WinID
), TRUE
);
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
);
871 setAspectRatio(vo_keepaspect
? KVAR_FORCEANY
: KVAR_NONE
);
874 WinCalcFrameRect(m_int
.hwndFrame
, &rcl
, FALSE
);
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));
885 static int color_ctrl_set(char *what
, int value
)
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"))
896 else if (!strcmp(what
, "saturation"))
897 ulAttr
= KVAA_SATURATION
;
901 ulValue
= (value
+ 100) * 255 / 200;
903 if (kvaSetAttr(ulAttr
, &ulValue
))
909 static int color_ctrl_get(char *what
, int *value
)
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"))
920 else if (!strcmp(what
, "saturation"))
921 ulAttr
= KVAA_SATURATION
;
925 if (kvaQueryAttr(ulAttr
, &ulValue
))
928 // add 1 to adjust range
929 *value
= ((ulValue
+ 1) * 200 / 255) - 100;
934 static int control(uint32_t request
, void *data
, ...)
937 case VOCTRL_GET_IMAGE
:
938 return get_image(data
);
940 case VOCTRL_DRAW_IMAGE
:
941 return draw_image(data
);
943 case VOCTRL_QUERY_FORMAT
:
944 return query_format(*(uint32_t *)data
);
946 case VOCTRL_FULLSCREEN
:
949 case VOCTRL_SET_EQUALIZER
:
955 value
= va_arg(ap
, int);
958 return color_ctrl_set(data
, value
);
961 case VOCTRL_GET_EQUALIZER
:
967 value
= va_arg(ap
, int *);
970 return color_ctrl_get(data
, value
);
973 case VOCTRL_UPDATE_SCREENINFO
:
974 vo_screenwidth
= m_int
.kvac
.cxScreen
;
975 vo_screenheight
= m_int
.kvac
.cyScreen
;
977 aspect_save_screenres(vo_screenwidth
, vo_screenheight
);
985 static int draw_frame(uint8_t *src
[])
990 static int draw_slice(uint8_t *src
[], int stride
[], int w
, int h
, int x
, int y
)
996 d
= m_int
.planes
[0] + m_int
.stride
[0] * y
+ x
;
998 mem2agpcpy_pic(d
, s
, w
* m_int
.bpp
, h
, m_int
.stride
[0], stride
[0]);
1001 if (m_int
.nChromaShift
) {
1002 w
>>= m_int
.nChromaShift
; h
>>= m_int
.nChromaShift
;
1003 x
>>= m_int
.nChromaShift
; y
>>= m_int
.nChromaShift
;
1006 d
= m_int
.planes
[1] + m_int
.stride
[1] * y
+ x
;
1008 mem2agpcpy_pic(d
, s
, w
, h
, m_int
.stride
[1], stride
[1]);
1011 d
= m_int
.planes
[2] + m_int
.stride
[2] * y
+ x
;
1013 mem2agpcpy_pic(d
, s
, w
, h
, m_int
.stride
[2], stride
[2]);
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, \
1024 static void draw_alpha(int x0
, int y0
, int w
, int h
,
1025 unsigned char *src
, unsigned char *srca
, int stride
)
1027 switch (m_int
.iImageFormat
) {
1030 vo_draw_alpha(yv12
);
1034 vo_draw_alpha(yuy2
);
1038 vo_draw_alpha(rgb24
);
1042 vo_draw_alpha(rgb16
);
1046 vo_draw_alpha(rgb15
);
1051 static void draw_osd(void)
1053 vo_draw_text(SRC_WIDTH
, SRC_HEIGHT
, draw_alpha
);
1056 static void flip_page(void)
1061 static void check_events(void)
1065 // On slave mode, we need to change our window size according to a
1066 // parent window size
1070 WinQueryWindowRect(HWNDFROMWINID(WinID
), &rcl
);
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
);
1081 m_int
.rclParent
= rcl
;
1085 while (WinPeekMsg(m_int
.hab
, &qm
, NULLHANDLE
, 0, 0, PM_REMOVE
))
1086 WinDispatchMsg(m_int
.hab
, &qm
);