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 "input/keycodes.h"
47 #include "input/input.h"
48 #include "subopt-helper.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",
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
, ' '},
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
},
82 {VK_RIGHT
, KEY_RIGHT
}, {VK_LEFT
, KEY_LEFT
},
83 {VK_DOWN
, KEY_DOWN
}, {VK_UP
, KEY_UP
},
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},
93 static const struct mp_keymap m_keypad_map
[] = {
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
},
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
},
132 uint8_t *planes
[MP_MAX_PLANES
]; // y = 0, u = 1, v = 2
133 int stride
[MP_MAX_PLANES
];
136 struct SwsContext
*sws
;
139 static inline void setAspectRatio(ULONG ulRatio
)
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
)
164 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YV12
;
171 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YUY2
;
178 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_YVU9
;
185 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR24
;
192 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR16
;
199 fHWAccel
= m_int
.kvac
.ulInputFormatFlags
& KVAF_BGR15
;
210 *pfHWAccel
= fHWAccel
;
219 *pnChromaShift
= nChromaShift
;
224 static void imgCreate(void)
226 int size
= SRC_HEIGHT
* m_int
.lStride
;;
228 switch (m_int
.iImageFormat
) {
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
;
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)
260 m_int
.pbImage
= NULL
;
263 static void imgDisplay(void)
268 if (!kvaLockBuffer(&pBuffer
, &ulBPL
)) {
269 uint8_t *dst
[MP_MAX_PLANES
] = {NULL
};
270 int dstStride
[MP_MAX_PLANES
] = {0};
274 dstStride
[0] = ulBPL
;
277 if (m_int
.nChromaShift
) {
279 dst
[2] = dst
[0] + SRC_HEIGHT
* dstStride
[0];
280 dstStride
[2] = dstStride
[0] >> m_int
.nChromaShift
;
284 (SRC_HEIGHT
>> m_int
.nChromaShift
) * dstStride
[2];
285 dstStride
[1] = dstStride
[2];
288 if (m_int
.fHWAccel
) {
295 mem2agpcpy_pic(dst
[0], m_int
.planes
[0], w
, h
,
296 dstStride
[0], m_int
.stride
[0]);
299 if (m_int
.nChromaShift
) {
300 w
>>= m_int
.nChromaShift
; h
>>= m_int
.nChromaShift
;
303 mem2agpcpy_pic(dst
[1], m_int
.planes
[1], w
, h
,
304 dstStride
[1], m_int
.stride
[1]);
307 mem2agpcpy_pic(dst
[2], m_int
.planes
[2], w
, h
,
308 dstStride
[2], m_int
.stride
[2]);
311 sws_scale(m_int
.sws
, m_int
.planes
, m_int
.stride
, 0, SRC_HEIGHT
,
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
,
325 case WM_QUERYTRACKINFO
:
327 PTRACKINFO pti
= (PTRACKINFO
)mp2
;
333 m_int
.pfnwpOldFrame(hwnd
, msg
, mp1
, mp2
);
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
;
359 if (pswp
->fl
& SWP_SIZE
) {
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
) {
377 rcl
.xRight
= vo_screenwidth
;
380 if (rcl
.yTop
- rcl
.yBottom
> vo_screenheight
) {
382 rcl
.yTop
= vo_screenheight
;
385 pswp
->fl
|= SWP_MOVE
;
387 pswp
->y
= rcl
.yBottom
;
388 pswp
->cx
= rcl
.xRight
- rcl
.xLeft
;
389 pswp
->cy
= rcl
.yTop
- rcl
.yBottom
;
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
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
;
411 mplayer_put_key(KEY_CLOSE_WIN
);
417 USHORT fsFlags
= SHORT1FROMMP(mp1
);
418 UCHAR uchScan
= CHAR4FROMMP(mp1
);
419 USHORT usCh
= SHORT1FROMMP(mp2
);
420 USHORT usVk
= SHORT2FROMMP(mp2
);
423 if (fsFlags
& KC_KEYUP
)
426 if (fsFlags
& KC_SCANCODE
) {
427 mpkey
= lookup_keymap_table(m_keypad_map
, uchScan
);
429 // distinguish KEY_KP0 and KEY_KPINS
430 if (mpkey
== KEY_KP0
&& usCh
!= '0')
433 // distinguish KEY_KPDEC and KEY_KPDEL
434 if (mpkey
== KEY_KPDEC
&& usCh
!= '.')
437 mplayer_put_key(mpkey
);
439 return (MRESULT
)TRUE
;
443 if (fsFlags
& KC_VIRTUALKEY
) {
444 mpkey
= lookup_keymap_table(m_vk_map
, usVk
);
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
;
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
;
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
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
)) {
507 for (i
= 0; i
< rgnCtl
.crcReturned
; i
++)
508 WinFillRect(hps
, &prcl
[i
], CLR_BLACK
);
513 GpiDestroyRegion(hps
, hrgnDst
);
514 GpiDestroyRegion(hps
, hrgn
);
522 return WinDefWindowProc(hwnd
, msg
, mp1
, mp2
);
525 // Change process type from VIO to PM to use PM APIs.
526 static void morphToPM(void)
530 DosGetInfoBlocks(NULL
, &pib
);
532 // Change flag from VIO to PM:
533 if (pib
->pib_ultype
== 2)
537 static int preinit(const char *arg
)
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)
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
,
571 CS_SIZEREDRAW
| CS_MOVENOTIFY
,
575 hwndParent
= HWND_DESKTOP
;
576 flFrameFlags
= FCF_SYSMENU
| FCF_TITLEBAR
| FCF_MINMAX
|
577 FCF_SIZEBORDER
| FCF_TASKLIST
;
581 hwndParent
= HWNDFROMWINID(WinID
);
584 // Prevent a parent window from painting over our window
585 ulStyle
= WinQueryWindowULong(hwndParent
, QWL_STYLE
);
586 WinSetWindowULong(hwndParent
, QWL_STYLE
, ulStyle
| WS_CLIPCHILDREN
);
590 WinCreateStdWindow(hwndParent
, // parent window handle
591 WS_VISIBLE
, // frame window style
592 &flFrameFlags
, // window style
593 WC_MPLAYER
, // class name
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
)
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
;
610 m_int
.pfnwpOldFrame
= WinSubclassWindow(m_int
.hwndFrame
,
613 if (!!fUseSnap
+ !!fUseWO
+ !!fUseDive
> 1)
614 mp_msg(MSGT_VO
, MSGL_WARN
,"KVA: Multiple mode specified!!!\n");
625 if (kvaInit(kvaMode
, m_int
.hwndClient
, vo_colorkey
)) {
626 mp_msg(MSGT_VO
, MSGL_ERR
, "KVA: Init failed!!!\n");
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
);
645 static void uninit(void)
647 kvaEnableScreenSaver();
651 sws_freeContext(m_int
.sws
);
653 if (m_int
.hwndFrame
!= NULLHANDLE
) {
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
)
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
);
679 if (query_format_info(format
, &m_int
.fHWAccel
, &m_int
.fcc
, &m_int
.bpp
,
680 &m_int
.nChromaShift
))
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
) {
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
))
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");
733 m_int
.lStride
= width
* m_int
.bpp
;
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
) {
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
;
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
;
776 WinQueryWindowRect(HWNDFROMWINID(WinID
), &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
);
793 static uint32_t get_image(mp_image_t
*mpi
)
795 if (m_int
.iImageFormat
!= mpi
->imgfmt
)
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
;
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
))
823 draw_slice(mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, mpi
->x
, mpi
->y
);
828 static int query_format(uint32_t format
)
833 if (query_format_info(format
, &fHWAccel
, NULL
, NULL
, NULL
))
836 res
= VFCAP_CSP_SUPPORTED
| VFCAP_OSD
;
838 res
|= VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_HWSCALE_UP
;
841 res
|= VFCAP_HWSCALE_DOWN
;
847 static int fs_toggle(void)
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
);
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
);
872 rcl
.xRight
= vo_screenwidth
;
873 rcl
.yTop
= vo_screenheight
;
875 setAspectRatio(KVAR_FORCEANY
);
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
);
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));
900 static int color_ctrl_set(char *what
, int value
)
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"))
911 else if (!strcmp(what
, "saturation"))
912 ulAttr
= KVAA_SATURATION
;
916 ulValue
= (value
+ 100) * 255 / 200;
918 if (kvaSetAttr(ulAttr
, &ulValue
))
924 static int color_ctrl_get(char *what
, int *value
)
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"))
935 else if (!strcmp(what
, "saturation"))
936 ulAttr
= KVAA_SATURATION
;
940 if (kvaQueryAttr(ulAttr
, &ulValue
))
943 // add 1 to adjust range
944 *value
= ((ulValue
+ 1) * 200 / 255) - 100;
949 static int control(uint32_t request
, void *data
)
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
:
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
);
988 static int draw_frame(uint8_t *src
[])
993 static int draw_slice(uint8_t *src
[], int stride
[], int w
, int h
, int x
, int y
)
999 d
= m_int
.planes
[0] + m_int
.stride
[0] * y
+ x
;
1001 mem2agpcpy_pic(d
, s
, w
* m_int
.bpp
, h
, m_int
.stride
[0], stride
[0]);
1004 if (m_int
.nChromaShift
) {
1005 w
>>= m_int
.nChromaShift
; h
>>= m_int
.nChromaShift
;
1006 x
>>= m_int
.nChromaShift
; y
>>= m_int
.nChromaShift
;
1009 d
= m_int
.planes
[1] + m_int
.stride
[1] * y
+ x
;
1011 mem2agpcpy_pic(d
, s
, w
, h
, m_int
.stride
[1], stride
[1]);
1014 d
= m_int
.planes
[2] + m_int
.stride
[2] * y
+ x
;
1016 mem2agpcpy_pic(d
, s
, w
, h
, m_int
.stride
[2], stride
[2]);
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, \
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
) {
1033 vo_draw_alpha(yv12
);
1037 vo_draw_alpha(yuy2
);
1041 vo_draw_alpha(rgb24
);
1045 vo_draw_alpha(rgb16
);
1049 vo_draw_alpha(rgb15
);
1054 static void draw_osd(void)
1056 vo_draw_text(SRC_WIDTH
, SRC_HEIGHT
, draw_alpha
);
1059 static void flip_page(void)
1064 static void check_events(void)
1068 // On slave mode, we need to change our window size according to a
1069 // parent window size
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
);