Mercurial > mplayer.hg
changeset 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 | f86b4bd1a060 |
children | 3c23b005eb98 |
files | Changelog DOCS/man/en/mplayer.1 Makefile configure libvo/video_out.c libvo/vo_kva.c |
diffstat | 6 files changed, 1139 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/Changelog Sat Mar 14 17:01:28 2009 +0000 +++ b/Changelog Sat Mar 14 18:44:58 2009 +0000 @@ -148,6 +148,7 @@ * removed unnecessary code from vo x11, xv, xvmc * add OS/2 DART audio driver (-ao dart) * add VDPAU video output + * add OS/2 KVA video driver (-vo kva) MEncoder: * check for system-wide configuration file in MEncoder
--- a/DOCS/man/en/mplayer.1 Sat Mar 14 17:01:28 2009 +0000 +++ b/DOCS/man/en/mplayer.1 Sat Mar 14 18:44:58 2009 +0000 @@ -3596,6 +3596,23 @@ .PD 1 . .TP +.B kva (OS/2 only) +Video output driver that uses the libkva interface. +.PD 0 +.RSs +.IPs snap +Force SNAP mode. +.IPs wo +Force WarpOverlay! mode. +.IPs dive +Force DIVE mode. +.IPs (no)t23 +Enable/disable workaround for T23 laptop (default: \-not23). +Try to enable this option if your video card supports upscaling only. +.RE +.PD 1 +. +.TP .B quartz (Mac OS X only) Mac OS X Quartz video output driver. Under some circumstances, it might be more efficient to force a
--- a/Makefile Sat Mar 14 17:01:28 2009 +0000 +++ b/Makefile Sat Mar 14 18:44:58 2009 +0000 @@ -596,6 +596,7 @@ SRCS_MPLAYER-$(JACK) += libao2/ao_jack.c SRCS_MPLAYER-$(JOYSTICK) += input/joystick.c SRCS_MPLAYER-$(JPEG) += libvo/vo_jpeg.c +SRCS_MPLAYER-$(KVA) += libvo/vo_kva.c SRCS_MPLAYER-$(LIBMENU) += libmenu/menu.c \ libmenu/menu_chapsel.c \ libmenu/menu_cmdlist.c \
--- a/configure Sat Mar 14 17:01:28 2009 +0000 +++ b/configure Sat Mar 14 18:44:58 2009 +0000 @@ -366,6 +366,7 @@ --enable-vesa enable VESA video output [autodetect] --enable-svga enable SVGAlib video output [autodetect] --enable-sdl enable SDL video output [autodetect] + --enable-kva enable KVA video output [autodetect] --enable-aa enable AAlib video output [autodetect] --enable-caca enable CACA video output [autodetect] --enable-ggi enable GGI video output [autodetect] @@ -556,6 +557,7 @@ _xvmc=no #auto when complete _vdpau=auto _sdl=auto +_kva=auto _direct3d=auto _directx=auto _win32waveout=auto @@ -888,6 +890,8 @@ --disable-vdpau) _vdpau=no ;; --enable-sdl) _sdl=yes ;; --disable-sdl) _sdl=no ;; + --enable-kva) _kva=yes ;; + --disable-kva) _kva=no ;; --enable-direct3d) _direct3d=yes ;; --disable-direct3d) _direct3d=no ;; --enable-directx) _directx=yes ;; @@ -5097,6 +5101,29 @@ echores "$_sdl" +if os2 ; then +echocheck "KVA (SNAP/WarpOverlay!/DIVE)" +if test "$_kva" = auto; then + cat > $TMPC << EOF +#include <os2.h> +#include <kva.h> +int main( void ) { return 0; } +EOF + _kva=no; + cc_check -lkva && _kva=yes +fi +if test "$_kva" = yes ; then + def_kva='#define CONFIG_KVA 1' + _libs_mplayer="$_libs_mplayer -lkva" + _vomodules="kva $_vomodules" +else + def_kva='#undef CONFIG_KVA' + _novomodules="kva $_novomodules" +fi +echores "$_kva" +fi #if os2 + + if win32; then echocheck "Windows waveout" @@ -8145,6 +8172,7 @@ JACK = $_jack JOYSTICK = $_joystick JPEG = $_jpeg +KVA = $_kva LADSPA = $_ladspa LIBA52 = $_liba52 LIBA52_INTERNAL = $_liba52_internal @@ -8647,6 +8675,7 @@ $def_gl_win32 $def_ivtv $def_jpeg +$def_kva $def_md5sum $def_mga $def_mng
--- a/libvo/video_out.c Sat Mar 14 17:01:28 2009 +0000 +++ b/libvo/video_out.c Sat Mar 14 18:44:58 2009 +0000 @@ -112,6 +112,7 @@ extern vo_functions_t video_out_yuv4mpeg; extern vo_functions_t video_out_direct3d; extern vo_functions_t video_out_directx; +extern vo_functions_t video_out_kva; extern vo_functions_t video_out_dxr2; extern vo_functions_t video_out_dxr3; extern vo_functions_t video_out_ivtv; @@ -146,6 +147,9 @@ #ifdef CONFIG_DIRECT3D &video_out_direct3d, #endif +#ifdef CONFIG_KVA + &video_out_kva, +#endif #ifdef CONFIG_COREVIDEO &video_out_macosx, #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libvo/vo_kva.c Sat Mar 14 18:44:58 2009 +0000 @@ -0,0 +1,1087 @@ +/* + * OS/2 video output driver + * + * Copyright (c) 2007-2009 by KO Myung-Hun (komh@chollian.net) + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define INCL_WIN +#define INCL_GPI +#define INCL_DOS +#include <os2.h> + +#include <mmioos2.h> +#include <fourcc.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> + +#include <kva.h> + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" +#include "video_out.h" +#include "video_out_internal.h" +#include "aspect.h" + +#include "fastmemcpy.h" +#include "mp_fifo.h" +#include "osdep/keycodes.h" +#include "input/input.h" +#include "input/mouse.h" +#include "subopt-helper.h" +#include "sub.h" + +#include "cpudetect.h" +#include "libswscale/swscale.h" +#include "libmpcodecs/vf_scale.h" + +static const vo_info_t info = { + "SNAP/WarpOverlay!/DIVE video output", + "kva", + "KO Myung-Hun <komh@chollian.net>", + "" +}; + +LIBVO_EXTERN(kva) + +#define WC_MPLAYER "WC_MPLAYER" + +#define SRC_WIDTH m_int.kvas.szlSrcSize.cx +#define SRC_HEIGHT m_int.kvas.szlSrcSize.cy + +#define HWNDFROMWINID(wid) ((wid) + 0x80000000UL) + +static const struct keymap m_vk_map[] = { + {VK_NEWLINE, KEY_ENTER}, {VK_TAB, KEY_TAB}, {VK_SPACE, ' '}, + + // control keys + {VK_CTRL, KEY_CTRL}, {VK_BACKSPACE, KEY_BS}, + {VK_DELETE, KEY_DELETE}, {VK_INSERT, KEY_INSERT}, + {VK_HOME, KEY_HOME}, {VK_END, KEY_END}, + {VK_PAGEUP, KEY_PAGE_UP}, {VK_PAGEDOWN, KEY_PAGE_DOWN}, + {VK_ESC, KEY_ESC}, + + // cursor keys + {VK_RIGHT, KEY_RIGHT}, {VK_LEFT, KEY_LEFT}, + {VK_DOWN, KEY_DOWN}, {VK_UP, KEY_UP}, + + // function keys + {VK_F1, KEY_F+1}, {VK_F2, KEY_F+2}, {VK_F3, KEY_F+3}, {VK_F4, KEY_F+4}, + {VK_F5, KEY_F+5}, {VK_F6, KEY_F+6}, {VK_F7, KEY_F+7}, {VK_F8, KEY_F+8}, + {VK_F9, KEY_F+9}, {VK_F10, KEY_F+10}, {VK_F11, KEY_F+11}, {VK_F12, KEY_F+12}, + + {0, 0} +}; + +static const struct keymap m_keypad_map[] = { + // keypad keys + {0x52, KEY_KP0}, {0x4F, KEY_KP1}, {0x50, KEY_KP2}, {0x51, KEY_KP3}, + {0x4B, KEY_KP4}, {0x4C, KEY_KP5}, {0x4D, KEY_KP6}, {0x47, KEY_KP7}, + {0x48, KEY_KP8}, {0x49, KEY_KP9}, {0x53, KEY_KPDEC}, {0x5A, KEY_KPENTER}, + + {0, 0} +}; + +static const struct keymap m_mouse_map[] = { + {WM_BUTTON1DOWN, MOUSE_BTN0}, + {WM_BUTTON3DOWN, MOUSE_BTN1}, + {WM_BUTTON2DOWN, MOUSE_BTN2}, + {WM_BUTTON1DBLCLK, MOUSE_BTN0_DBL}, + {WM_BUTTON3DBLCLK, MOUSE_BTN1_DBL}, + {WM_BUTTON2DBLCLK, MOUSE_BTN2_DBL}, + + {0, 0} +}; + +struct { + HAB hab; + HMQ hmq; + HWND hwndFrame; + HWND hwndClient; + HWND hwndSysMenu; + HWND hwndTitleBar; + HWND hwndMinMax; + FOURCC fcc; + int iImageFormat; + int nChromaShift; + KVASETUP kvas; + KVACAPS kvac; + RECTL rclDst; + int bpp; + LONG lStride; + PBYTE pbImage; + BOOL fFixT23; + PFNWP pfnwpOldFrame; + uint8_t *planes[3]; // y = 0, u = 1, v = 2 + int stride[3]; + BOOL fHWAccel; + RECTL rclParent; + struct SwsContext *sws; +} m_int; + +static inline void setAspectRatio(ULONG ulRatio) +{ + m_int.kvas.ulRatio = ulRatio; + kvaSetup(&m_int.kvas); +} + +static int query_format_info(int format, PBOOL pfHWAccel, PFOURCC pfcc, + int *pbpp, int *pnChromaShift) +{ + BOOL fHWAccel; + FOURCC fcc; + INT bpp; + INT nChromaShift; + + switch (format) { + case IMGFMT_YV12: + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YV12; + fcc = FOURCC_YV12; + bpp = 1; + nChromaShift = 1; + break; + + case IMGFMT_YUY2: + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YUY2; + fcc = FOURCC_Y422; + bpp = 2; + nChromaShift = 0; + break; + + case IMGFMT_YVU9: + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YVU9; + fcc = FOURCC_YVU9; + bpp = 1; + nChromaShift = 2; + break; + + case IMGFMT_BGR24: + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR24; + fcc = FOURCC_BGR3; + bpp = 3; + nChromaShift = 0; + break; + + case IMGFMT_BGR16: + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR16; + fcc = FOURCC_R565; + bpp = 2; + nChromaShift = 0; + break; + + case IMGFMT_BGR15: + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR15; + fcc = FOURCC_R555; + bpp = 2; + nChromaShift = 0; + break; + + default: + return 1; + } + + if (pfHWAccel) + *pfHWAccel = fHWAccel; + + if (pfcc) + *pfcc = fcc; + + if (pbpp) + *pbpp = bpp; + + if (pnChromaShift) + *pnChromaShift = nChromaShift; + + return 0; +} + +static void imgCreate(void) +{ + int size = SRC_HEIGHT * m_int.lStride;; + + switch (m_int.iImageFormat) { + case IMGFMT_YV12: + size += size / 2; + break; + + case IMGFMT_YVU9: + size += size / 8; + break; + } + + m_int.pbImage = malloc(size); + + m_int.planes[0] = m_int.pbImage; + m_int.stride[0] = m_int.lStride; + + // YV12 or YVU9 ? + if (m_int.nChromaShift) { + m_int.planes[1] = m_int.planes[0] + SRC_HEIGHT * m_int.stride[0]; + m_int.stride[1] = m_int.stride[0] >> m_int.nChromaShift; + + m_int.planes[2] = m_int.planes[1] + + (SRC_HEIGHT >> m_int.nChromaShift) * m_int.stride[1]; + m_int.stride[2] = m_int.stride[1]; + } +} + +static void imgFree(void) +{ + free(m_int.pbImage); + + m_int.pbImage = NULL; +} + +static void imgDisplay(void) +{ + PVOID pBuffer; + ULONG ulBPL; + + if (!kvaLockBuffer(&pBuffer, &ulBPL)) { + uint8_t *dst[3]; + int dstStride[3]; + + // Get packed or Y + dst[0] = pBuffer; + dstStride[0] = ulBPL; + + // YV12 or YVU9 ? + if (m_int.nChromaShift) { + // Get V + dst[2] = dst[0] + SRC_HEIGHT * dstStride[0]; + dstStride[2] = dstStride[0] >> m_int.nChromaShift; + + // Get U + dst[1] = dst[2] + + (SRC_HEIGHT >> m_int.nChromaShift ) * dstStride[2]; + dstStride[1] = dstStride[2]; + } + + if (m_int.fHWAccel) { + int w, h; + + w = m_int.stride[0]; + h = SRC_HEIGHT; + + // Copy packed or Y + mem2agpcpy_pic(dst[0], m_int.planes[0], w, h, + dstStride[0], m_int.stride[0]); + + // YV12 or YVU9 ? + if (m_int.nChromaShift) { + w >>= m_int.nChromaShift; h >>= m_int.nChromaShift; + + // Copy U + mem2agpcpy_pic(dst[1], m_int.planes[1], w, h, + dstStride[1], m_int.stride[1]); + + // Copy V + mem2agpcpy_pic(dst[2], m_int.planes[2], w, h, + dstStride[2], m_int.stride[2]); + } + } else { + sws_scale(m_int.sws, m_int.planes, m_int.stride, 0, SRC_HEIGHT, + dst, dstStride); + } + + kvaUnlockBuffer(); + } +} + +// Frame window procedure to work around T23 laptop with S3 video card, +// which supports upscaling only. +static MRESULT EXPENTRY NewFrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1, + MPARAM mp2) +{ + switch (msg) { + case WM_QUERYTRACKINFO: + { + PTRACKINFO pti = (PTRACKINFO)mp2; + RECTL rcl; + + if (vo_fs) + break; + + m_int.pfnwpOldFrame(hwnd, msg, mp1, mp2); + + rcl.xLeft = 0; + rcl.yBottom = 0; + rcl.xRight = SRC_WIDTH + 1; + rcl.yTop = SRC_HEIGHT + 1; + + WinCalcFrameRect(hwnd, &rcl, FALSE); + + pti->ptlMinTrackSize.x = rcl.xRight - rcl.xLeft; + pti->ptlMinTrackSize.y = rcl.yTop - rcl.yBottom; + + pti->ptlMaxTrackSize.x = vo_screenwidth; + pti->ptlMaxTrackSize.y = vo_screenheight; + + return (MRESULT)TRUE; + } + + case WM_ADJUSTWINDOWPOS: + { + PSWP pswp = (PSWP)mp1; + RECTL rcl; + + if (vo_fs) + break; + + if (pswp->fl & SWP_SIZE) { + rcl.xLeft = pswp->x; + rcl.yBottom = pswp->y; + rcl.xRight = rcl.xLeft + pswp->cx; + rcl.yTop = rcl.yBottom + pswp->cy; + + WinCalcFrameRect(hwnd, &rcl, TRUE); + + if (rcl.xRight - rcl.xLeft <= SRC_WIDTH) + rcl.xRight = rcl.xLeft + (SRC_WIDTH + 1); + + if (rcl.yTop - rcl.yBottom <= SRC_HEIGHT) + rcl.yTop = rcl.yBottom + (SRC_HEIGHT + 1); + + WinCalcFrameRect(hwnd, &rcl, FALSE); + + if (rcl.xRight - rcl.xLeft > vo_screenwidth) { + rcl.xLeft = 0; + rcl.xRight = vo_screenwidth; + } + + if (rcl.yTop - rcl.yBottom > vo_screenheight) { + rcl.yBottom = 0; + rcl.yTop = vo_screenheight; + } + + pswp->fl |= SWP_MOVE; + pswp->x = rcl.xLeft; + pswp->y = rcl.yBottom; + pswp->cx = rcl.xRight - rcl.xLeft; + pswp->cy = rcl.yTop - rcl.yBottom; + } + break; + } + } + + return m_int.pfnwpOldFrame(hwnd, msg, mp1, mp2); +} + +static MRESULT EXPENTRY WndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + // if slave mode, ignore mouse events and deliver them to a parent window + if (WinID != -1 && + ((msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) || + (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST))) { + WinPostMsg(HWNDFROMWINID(WinID), msg, mp1, mp2); + + return (MRESULT)TRUE; + } + + switch (msg) { + case WM_CLOSE: + mplayer_put_key(KEY_CLOSE_WIN); + + return 0; + + case WM_CHAR: + { + USHORT fsFlags = SHORT1FROMMP(mp1); + UCHAR uchScan = CHAR4FROMMP(mp1); + USHORT usCh = SHORT1FROMMP(mp2); + USHORT usVk = SHORT2FROMMP(mp2); + int mpkey; + + if (fsFlags & KC_KEYUP) + break; + + if (fsFlags & KC_SCANCODE) { + mpkey = lookup_keymap_table(m_keypad_map, uchScan); + if (mpkey) { + // distinguish KEY_KP0 and KEY_KPINS + if (mpkey == KEY_KP0 && usCh != '0') + mpkey = KEY_KPINS; + + // distinguish KEY_KPDEC and KEY_KPDEL + if (mpkey == KEY_KPDEC && usCh != '.') + mpkey = KEY_KPDEL; + + mplayer_put_key(mpkey); + + return (MRESULT)TRUE; + } + } + + if (fsFlags & KC_VIRTUALKEY) { + mpkey = lookup_keymap_table(m_vk_map, usVk); + if (mpkey) { + mplayer_put_key(mpkey); + + return (MRESULT)TRUE; + } + } + + if ((fsFlags & KC_CHAR) && !HIBYTE(usCh)) + mplayer_put_key(usCh); + + return (MRESULT)TRUE; + } + + case WM_BUTTON1DOWN: + case WM_BUTTON3DOWN: + case WM_BUTTON2DOWN: + case WM_BUTTON1DBLCLK: + case WM_BUTTON3DBLCLK: + case WM_BUTTON2DBLCLK: + if (WinQueryFocus(HWND_DESKTOP) != hwnd) + WinSetFocus(HWND_DESKTOP, hwnd); + else if (!vo_nomouse_input) + mplayer_put_key(lookup_keymap_table(m_mouse_map, msg)); + + return (MRESULT)TRUE; + + case WM_PAINT: + { + HPS hps; + RECTL rcl, rclDst; + PRECTL prcl = NULL; + HRGN hrgn, hrgnDst; + RGNRECT rgnCtl; + + // get a current movie area + kvaAdjustDstRect(&m_int.kvas.rclSrcRect, &rclDst); + + // get a current invalidated area + hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl); + + // create a region for an invalidated area + hrgn = GpiCreateRegion(hps, 1, &rcl); + // create a region for a movie area + hrgnDst = GpiCreateRegion(hps, 1, &rclDst); + + // exclude a movie area from an invalidated area + GpiCombineRegion(hps, hrgn, hrgn, hrgnDst, CRGN_DIFF); + + // get rectangles from the region + rgnCtl.ircStart = 1; + rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT; + GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, NULL); + + if (rgnCtl.crcReturned > 0) { + rgnCtl.crc = rgnCtl.crcReturned; + prcl = malloc(sizeof(RECTL) * rgnCtl.crcReturned); + } + + // draw black bar if needed + if (prcl && GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, prcl)) { + int i; + + for (i = 0; i < rgnCtl.crcReturned; i++) + WinFillRect(hps, &prcl[i], CLR_BLACK); + } + + free(prcl); + + GpiDestroyRegion(hps, hrgnDst); + GpiDestroyRegion(hps, hrgn); + + WinEndPaint(hps); + + return 0; + } + } + + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +// Change process type from VIO to PM to use PM APIs. +static void morphToPM(void) +{ + PPIB pib; + + DosGetInfoBlocks(NULL, &pib); + + // Change flag from VIO to PM: + if (pib->pib_ultype == 2) + pib->pib_ultype = 3; +} + +static int preinit(const char *arg) +{ + HWND hwndParent; + ULONG flFrameFlags; + ULONG kvaMode = 0; + + int fUseSnap = 0; + int fUseWO = 0; + int fUseDive = 0; + int fFixT23 = 0; + + const opt_t subopts[] = { + {"snap", OPT_ARG_BOOL, &fUseSnap, NULL}, + {"wo", OPT_ARG_BOOL, &fUseWO, NULL}, + {"dive", OPT_ARG_BOOL, &fUseDive, NULL}, + {"t23", OPT_ARG_BOOL, &fFixT23, NULL}, + {NULL, 0, NULL, NULL} + }; + + PCSZ pcszVideoModeStr[3] = {"DIVE", "WarpOverlay!", "SNAP"}; + + if (subopt_parse(arg, subopts) != 0) + return -1; + + morphToPM(); + + memset(&m_int, 0, sizeof(m_int)); + + m_int.hab = WinInitialize(0); + m_int.hmq = WinCreateMsgQueue(m_int.hab, 0); + + WinRegisterClass(m_int.hab, + WC_MPLAYER, + WndProc, + CS_SIZEREDRAW | CS_MOVENOTIFY, + sizeof(PVOID)); + + if (WinID == -1) { + hwndParent = HWND_DESKTOP; + flFrameFlags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX | + FCF_SIZEBORDER | FCF_TASKLIST; + } else { + hwndParent = HWNDFROMWINID(WinID); + flFrameFlags = 0; + } + + m_int.hwndFrame = + WinCreateStdWindow(hwndParent, // parent window handle + WS_VISIBLE, // frame window style + &flFrameFlags, // window style + WC_MPLAYER, // class name + "", // window title + 0L, // default client style + NULLHANDLE, // resource in exe file + 1, // frame window id + &m_int.hwndClient); // client window handle + + if (m_int.hwndFrame == NULLHANDLE) + return -1; + + m_int.hwndSysMenu = WinWindowFromID(m_int.hwndFrame, FID_SYSMENU); + m_int.hwndTitleBar = WinWindowFromID(m_int.hwndFrame, FID_TITLEBAR); + m_int.hwndMinMax = WinWindowFromID(m_int.hwndFrame, FID_MINMAX); + + m_int.fFixT23 = fFixT23; + + if (m_int.fFixT23) + m_int.pfnwpOldFrame = WinSubclassWindow(m_int.hwndFrame, + NewFrameWndProc); + + if (!!fUseSnap + !!fUseWO + !!fUseDive > 1) + mp_msg(MSGT_VO, MSGL_WARN,"KVA: Multiple mode specified!!!\n"); + + if (fUseSnap) + kvaMode = KVAM_SNAP; + else if (fUseWO) + kvaMode = KVAM_WO; + else if (fUseDive) + kvaMode = KVAM_DIVE; + else + kvaMode = KVAM_AUTO; + + if (kvaInit(kvaMode, m_int.hwndClient, vo_colorkey)) { + mp_msg(MSGT_VO, MSGL_ERR, "KVA: Init failed!!!\n"); + + return -1; + } + + kvaCaps(&m_int.kvac); + + mp_msg(MSGT_VO, MSGL_V, "KVA: Selected video mode = %s\n", + pcszVideoModeStr[m_int.kvac.ulMode - 1]); + + kvaDisableScreenSaver(); + + // Might cause PM DLLs to be loaded which incorrectly enable SIG_FPE, + // so mask off all floating-point exceptions. + _control87(MCW_EM, MCW_EM); + + return 0; +} + +static void uninit(void) +{ + kvaEnableScreenSaver(); + + imgFree(); + + sws_freeContext(m_int.sws); + + if (m_int.hwndFrame != NULLHANDLE) { + kvaResetAttr(); + kvaDone(); + + if (m_int.fFixT23) + WinSubclassWindow(m_int.hwndFrame, m_int.pfnwpOldFrame); + + WinDestroyWindow(m_int.hwndFrame); + } + + WinDestroyMsgQueue(m_int.hmq); + WinTerminate(m_int.hab); +} + +static int config(uint32_t width, uint32_t height, + uint32_t d_width, uint32_t d_height, + uint32_t flags, char *title, uint32_t format) +{ + RECTL rcl; + + mp_msg(MSGT_VO, MSGL_V, + "KVA: Using 0x%X (%s) image format, vo_config_count = %d\n", + format, vo_format_name(format), vo_config_count); + + imgFree(); + + if (query_format_info(format, &m_int.fHWAccel, &m_int.fcc, &m_int.bpp, + &m_int.nChromaShift)) + return 1; + + m_int.iImageFormat = format; + + // if there is no hw accel for given format, + // try any format supported by hw accel + if (!m_int.fHWAccel) { + int dstFormat = 0; + + sws_freeContext(m_int.sws); + + if (m_int.kvac.ulInputFormatFlags & KVAF_YV12) + dstFormat = IMGFMT_YV12; + else if (m_int.kvac.ulInputFormatFlags & KVAF_YUY2) + dstFormat = IMGFMT_YUY2; + else if (m_int.kvac.ulInputFormatFlags & KVAF_YVU9) + dstFormat = IMGFMT_YVU9; + else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR24) + dstFormat = IMGFMT_BGR24; + else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR16) + dstFormat = IMGFMT_BGR16; + else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR15) + dstFormat = IMGFMT_BGR15; + + if (query_format_info(dstFormat, NULL, &m_int.fcc, NULL, NULL)) + return 1; + + m_int.sws = sws_getContextFromCmdLine(width, height, format, + width, height, dstFormat); + } + + mp_msg(MSGT_VO, MSGL_V, "KVA: Selected FOURCC = %.4s\n", (char *)&m_int.fcc); + + m_int.kvas.ulLength = sizeof(KVASETUP); + m_int.kvas.szlSrcSize.cx = width; + m_int.kvas.szlSrcSize.cy = height; + m_int.kvas.rclSrcRect.xLeft = 0; + m_int.kvas.rclSrcRect.yTop = 0; + m_int.kvas.rclSrcRect.xRight = width; + m_int.kvas.rclSrcRect.yBottom = height; + m_int.kvas.ulRatio = vo_keepaspect ? KVAR_FORCEANY : KVAR_NONE; + m_int.kvas.ulAspectWidth = d_width; + m_int.kvas.ulAspectHeight = d_height; + m_int.kvas.fccSrcColor = m_int.fcc; + m_int.kvas.fDither = TRUE; + + if (kvaSetup(&m_int.kvas)) { + mp_msg(MSGT_VO, MSGL_ERR, "KVA: Setup failed!!!\n"); + + return 1; + } + + m_int.lStride = width * m_int.bpp; + + imgCreate(); + + if (WinID == -1) { + WinSetWindowText(m_int.hwndFrame, title); + + // initialize 'vo_fs' only once at first config() call + if (vo_config_count == 0) + vo_fs = flags & VOFLAG_FULLSCREEN; + + // workaround for T23 laptop with S3 Video by Franz Bakan + if (!vo_fs && m_int.fFixT23) { + d_width++; + d_height++; + } + + m_int.rclDst.xLeft = ((LONG)vo_screenwidth - (LONG)d_width) / 2; + m_int.rclDst.yBottom = ((LONG)vo_screenheight - (LONG)d_height) / 2; + m_int.rclDst.xRight = m_int.rclDst.xLeft + d_width; + m_int.rclDst.yTop = m_int.rclDst.yBottom + d_height; + + if (vo_fs) { + d_width = vo_screenwidth; + d_height = vo_screenheight; + + // when -fs option is used without this, title bar is not highlighted + WinSetActiveWindow(HWND_DESKTOP, m_int.hwndFrame); + + WinSetParent(m_int.hwndSysMenu, HWND_OBJECT, FALSE); + WinSetParent(m_int.hwndTitleBar, HWND_OBJECT, FALSE); + WinSetParent(m_int.hwndMinMax, HWND_OBJECT, FALSE); + + setAspectRatio(KVAR_FORCEANY); + } + + rcl.xLeft = ((LONG)vo_screenwidth - (LONG)d_width) / 2; + rcl.yBottom = ((LONG)vo_screenheight - (LONG)d_height) /2 ; + rcl.xRight = rcl.xLeft + d_width; + rcl.yTop = rcl.yBottom + d_height; + } else { + vo_fs = 0; + + WinQueryWindowRect(HWNDFROMWINID(WinID), &m_int.rclDst); + rcl = m_int.rclDst; + } + + WinCalcFrameRect(m_int.hwndFrame, &rcl, FALSE); + + WinSetWindowPos(m_int.hwndFrame, HWND_TOP, + rcl.xLeft, rcl.yBottom, + rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, + SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW | + (WinID == -1 ? SWP_ACTIVATE : 0)); + + WinInvalidateRect(m_int.hwndFrame, NULL, TRUE); + + return 0; +} + +static uint32_t get_image(mp_image_t *mpi) +{ + if (m_int.iImageFormat != mpi->imgfmt) + return VO_FALSE; + + if (mpi->type == MP_IMGTYPE_STATIC || mpi->type == MP_IMGTYPE_TEMP) { + if (mpi->flags & MP_IMGFLAG_PLANAR) { + mpi->planes[1] = m_int.planes[1]; + mpi->planes[2] = m_int.planes[2]; + + mpi->stride[1] = m_int.stride[1]; + mpi->stride[2] = m_int.stride[2]; + } + + mpi->planes[0] = m_int.planes[0]; + mpi->stride[0] = m_int.stride[0]; + mpi->flags |= MP_IMGFLAG_DIRECT; + + return VO_TRUE; + } + + return VO_FALSE; +} + +static uint32_t draw_image(mp_image_t *mpi) +{ + // if -dr or -slices then do nothing: + if (mpi->flags & (MP_IMGFLAG_DIRECT | MP_IMGFLAG_DRAW_CALLBACK)) + return VO_TRUE; + + draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, mpi->x, mpi->y); + + return VO_TRUE; +} + +static int query_format(uint32_t format) +{ + BOOL fHWAccel; + int res; + + if (query_format_info(format, &fHWAccel, NULL, NULL, NULL)) + return 0; + + res = VFCAP_CSP_SUPPORTED | VFCAP_OSD; + if (fHWAccel) { + res |= VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP; + + if (!m_int.fFixT23) + res |= VFCAP_HWSCALE_DOWN; + } + + return res; +} + +static int fs_toggle(void) +{ + RECTL rcl; + + vo_fs = !vo_fs; + + if (vo_fs) { + SWP swp; + + WinQueryWindowPos(m_int.hwndFrame, &swp); + m_int.rclDst.xLeft = swp.x; + m_int.rclDst.yBottom = swp.y; + m_int.rclDst.xRight = m_int.rclDst.xLeft + swp.cx; + m_int.rclDst.yTop = m_int.rclDst.yBottom + swp.cy; + WinCalcFrameRect(m_int.hwndFrame, &m_int.rclDst, TRUE); + + if (WinID != -1) + WinSetParent(m_int.hwndFrame, HWND_DESKTOP, FALSE); + + WinSetParent(m_int.hwndSysMenu, HWND_OBJECT, FALSE); + WinSetParent(m_int.hwndTitleBar, HWND_OBJECT, FALSE); + WinSetParent(m_int.hwndMinMax, HWND_OBJECT, FALSE); + + rcl.xLeft = 0; + rcl.yBottom = 0; + rcl.xRight = vo_screenwidth; + rcl.yTop = vo_screenheight; + + setAspectRatio(KVAR_FORCEANY); + } else { + if (WinID != -1) + WinSetParent(m_int.hwndFrame, HWNDFROMWINID(WinID), TRUE); + + WinSetParent(m_int.hwndSysMenu, m_int.hwndFrame, FALSE); + WinSetParent(m_int.hwndTitleBar, m_int.hwndFrame, FALSE); + WinSetParent(m_int.hwndMinMax, m_int.hwndFrame, FALSE); + + rcl = m_int.rclDst; + + setAspectRatio(vo_keepaspect ? KVAR_FORCEANY : KVAR_NONE); + } + + WinCalcFrameRect(m_int.hwndFrame, &rcl, FALSE); + + WinSetWindowPos(m_int.hwndFrame, HWND_TOP, + rcl.xLeft, rcl.yBottom, + rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, + SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW | + (WinID == -1 ? SWP_ACTIVATE : 0)); + + return VO_TRUE; +} + +static int color_ctrl_set(char *what, int value) +{ + ULONG ulAttr; + ULONG ulValue; + + if (!strcmp(what, "brightness")) + ulAttr = KVAA_BRIGHTNESS; + else if (!strcmp(what, "contrast")) + ulAttr = KVAA_CONTRAST; + else if (!strcmp(what, "hue")) + ulAttr = KVAA_HUE; + else if (!strcmp(what, "saturation")) + ulAttr = KVAA_SATURATION; + else + return VO_NOTIMPL; + + ulValue = (value + 100) * 255 / 200; + + if (kvaSetAttr(ulAttr, &ulValue)) + return VO_NOTIMPL; + + return VO_TRUE; +} + +static int color_ctrl_get(char *what, int *value) +{ + ULONG ulAttr; + ULONG ulValue; + + if (!strcmp(what, "brightness")) + ulAttr = KVAA_BRIGHTNESS; + else if (!strcmp(what, "contrast")) + ulAttr = KVAA_CONTRAST; + else if (!strcmp(what, "hue")) + ulAttr = KVAA_HUE; + else if (!strcmp(what, "saturation")) + ulAttr = KVAA_SATURATION; + else + return VO_NOTIMPL; + + if (kvaQueryAttr(ulAttr, &ulValue)) + return VO_NOTIMPL; + + // add 1 to adjust range + *value = ((ulValue + 1) * 200 / 255) - 100; + + return VO_TRUE; +} + +static int control(uint32_t request, void *data, ...) +{ + switch (request) { + case VOCTRL_GET_IMAGE: + return get_image(data); + + case VOCTRL_DRAW_IMAGE: + return draw_image(data); + + case VOCTRL_QUERY_FORMAT: + return query_format(*(uint32_t *)data); + + case VOCTRL_FULLSCREEN: + return fs_toggle(); + + case VOCTRL_SET_EQUALIZER: + { + va_list ap; + int value; + + va_start(ap, data); + value = va_arg(ap, int); + va_end(ap); + + return color_ctrl_set(data, value); + } + + case VOCTRL_GET_EQUALIZER: + { + va_list ap; + int *value; + + va_start(ap, data); + value = va_arg(ap, int *); + va_end(ap); + + return color_ctrl_get(data, value); + } + + case VOCTRL_UPDATE_SCREENINFO: + vo_screenwidth = m_int.kvac.cxScreen; + vo_screenheight = m_int.kvac.cyScreen; + + aspect_save_screenres(vo_screenwidth, vo_screenheight); + + return VO_TRUE; + } + + return VO_NOTIMPL; +} + +static int draw_frame(uint8_t *src[]) +{ + return VO_ERROR; +} + +static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y) +{ + uint8_t *s; + uint8_t *d; + + // copy packed or Y + d = m_int.planes[0] + m_int.stride[0] * y + x; + s = src[0]; + mem2agpcpy_pic(d, s, w * m_int.bpp, h, m_int.stride[0], stride[0]); + + // YV12 or YVU9 + if (m_int.nChromaShift) { + w >>= m_int.nChromaShift; h >>= m_int.nChromaShift; + x >>= m_int.nChromaShift; y >>= m_int.nChromaShift; + + // copy U + d = m_int.planes[1] + m_int.stride[1] * y + x; + s = src[1]; + mem2agpcpy_pic(d, s, w, h, m_int.stride[1], stride[1]); + + // copy V + d = m_int.planes[2] + m_int.stride[2] * y + x; + s = src[2]; + mem2agpcpy_pic(d, s, w, h, m_int.stride[2], stride[2]); + } + + return 0; +} + +#define vo_draw_alpha(imgfmt) \ + vo_draw_alpha_##imgfmt(w, h, src, srca, stride, \ + m_int.planes[0] + m_int.stride[0] * y0 + m_int.bpp * x0, \ + m_int.stride[0]) + +static void draw_alpha(int x0, int y0, int w, int h, + unsigned char *src, unsigned char *srca, int stride) +{ + switch (m_int.iImageFormat) { + case IMGFMT_YV12: + case IMGFMT_YVU9: + vo_draw_alpha(yv12); + break; + + case IMGFMT_YUY2: + vo_draw_alpha(yuy2); + break; + + case IMGFMT_BGR24: + vo_draw_alpha(rgb24); + break; + + case IMGFMT_BGR16: + vo_draw_alpha(rgb16); + break; + + case IMGFMT_BGR15: + vo_draw_alpha(rgb15); + break; + } +} + +static void draw_osd(void) +{ + vo_draw_text(SRC_WIDTH, SRC_HEIGHT, draw_alpha); +} + +static void flip_page(void) +{ + imgDisplay(); +} + +static void check_events(void) +{ + QMSG qm; + + // On slave mode, we need to change our window size according to a + // parent window size + if (WinID != -1) { + RECTL rcl; + + WinQueryWindowRect(HWNDFROMWINID(WinID), &rcl); + + if (rcl.xLeft != m_int.rclParent.xLeft || + rcl.yBottom != m_int.rclParent.yBottom || + rcl.xRight != m_int.rclParent.xRight || + rcl.yTop != m_int.rclParent.yTop) { + WinSetWindowPos(m_int.hwndFrame, NULLHANDLE, + rcl.xLeft, rcl.yBottom, + rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, + SWP_SIZE | SWP_MOVE); + + m_int.rclParent = rcl; + } + } + + while (WinPeekMsg(m_int.hab, &qm, NULLHANDLE, 0, 0, PM_REMOVE)) + WinDispatchMsg(m_int.hab, &qm); +}