Index: Makefile =================================================================== --- Makefile (revision 28767) +++ Makefile (working copy) @@ -599,6 +600,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 \ Index: libvo/video_out.c =================================================================== --- libvo/video_out.c (revision 28767) +++ libvo/video_out.c (working copy) @@ -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 Index: libvo/vo_kva.c =================================================================== --- libvo/vo_kva.c (revision 0) +++ libvo/vo_kva.c (revision 0) @@ -0,0 +1,1202 @@ +/* + * 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 + +#include +#include + +#include +#include +#include +#include + +#include + +#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 vo_info_t info = { + "SNAP/WarpOverlay!/DIVE video output", + "kva", + "KO Myung-Hun ", + "" +}; + +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) + +#define SET_ASPECT_RATIO(ratio) {\ + m_int.kvas.ulRatio = (ratio);\ + kvaSetup(&m_int.kvas);\ +} + +struct tagVOKVAINTERNAL { + HAB hab; + HMQ hmq; + HWND hwndFrame; + HWND hwndClient; + HWND hwndSysMenu; + HWND hwndTitleBar; + HWND hwndMinMax; + FOURCC fcc; + INT iImageFormat; + 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; +}; + +static struct tagVOKVAINTERNAL m_int; + +static void imgCreate(void) +{ + int size; + int n; + + size = SRC_HEIGHT * m_int.lStride; + + switch (m_int.iImageFormat) { + case IMGFMT_YV12 : + size += size / 2; + n = 2; + break; + + case IMGFMT_YVU9 : + size += size / 8; + n = 4; + break; + + default : + n = 0; + break; + } + + m_int.pbImage = malloc(size); + + m_int.planes[0] = m_int.pbImage; + m_int.stride[0] = m_int.lStride; + + // YV12 or YVU9 ? + if (n) { + m_int.planes[1] = m_int.planes[0] + SRC_HEIGHT * m_int.stride[0]; + m_int.stride[1] = m_int.stride[0] / n; + + m_int.planes[2] = m_int.planes[1] + (SRC_HEIGHT / n) * m_int.stride[1]; + m_int.stride[2] = m_int.stride[1]; + } +} + +static void imgFree(void) +{ + if (m_int.pbImage) + free(m_int.pbImage); + + m_int.pbImage = NULL; +} + +static void imgDisplay(void) +{ + PVOID pBuffer; + ULONG ulBPL; + + if (!kvaLockBuffer(&pBuffer, &ulBPL)) { + uint8_t *dst[3] = {NULL,}; + int dstStride[3] = {0,}; + int n; + + switch (m_int.fcc) { + case FOURCC_YV12 : + n = 2; + break; + + case FOURCC_YVU9 : + n = 4; + break; + + default : + n = 0; + break; + } + + // Get packed or Y + dst[0] = pBuffer; + dstStride[0] = ulBPL; + + // YV12 or YVU9 ? + if (n) { + // Get V + dst[2] = dst[0] + SRC_HEIGHT * dstStride[0]; + dstStride[2] = dstStride[0] / n; + + // Get U + dst[1] = dst[2] + (SRC_HEIGHT / n) * 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 (n) { + w /= n; h /= n; + + // 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); + + if (gCpuCaps.hasMMX) + asm volatile ("emms\n\t"); + } + + kvaUnlockBuffer(); + } +} + +#define MRETURN(ret) return (MRESULT)(ret) + +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); + +#if 0 + // constrain a window in a screen + pti->rclBoundary.xLeft = 0; + pti->rclBoundary.yBottom = 0; + pti->rclBoundary.xRight = vo_screenwidth; + pti->rclBoundary.yTop = vo_screenheight; +#endif + + 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; + + MRETURN(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; + } + } + + MRETURN(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); + + MRETURN(TRUE); + } + + switch (msg) { + case WM_CLOSE : + mplayer_put_key(KEY_CLOSE_WIN); + + MRETURN(0); + + case WM_CHAR : + { + USHORT fsFlags = SHORT1FROMMP(mp1); + UCHAR uchScan = CHAR4FROMMP(mp1); + USHORT usCh = SHORT1FROMMP(mp2); + USHORT usVk = SHORT2FROMMP(mp2); + + if (fsFlags & KC_KEYUP) + break; + + if (fsFlags & KC_SCANCODE) { + switch (uchScan) { + case 0x52 : // KP0, KPINS + mplayer_put_key(usCh == '0' ? KEY_KP0 : KEY_KPINS); + fsFlags = 0; // Clear flags + break; + + case 0x4F : // KP1 + mplayer_put_key(KEY_KP1); + fsFlags = 0; // Clear flags + break; + + case 0x50 : // KP2 + mplayer_put_key(KEY_KP2); + fsFlags = 0; // Clear flags + break; + + case 0x51 : // KP3 + mplayer_put_key(KEY_KP3); + fsFlags = 0; // Clear flags + break; + + case 0x4B : // KP4 + mplayer_put_key(KEY_KP4); + fsFlags = 0; // Clear flags + break; + + case 0x4C : // KP5 + mplayer_put_key(KEY_KP5); + fsFlags = 0; // Clear flags + break; + + case 0x4D : // KP6 + mplayer_put_key(KEY_KP6); + fsFlags = 0; // Clear flags + break; + + case 0x47 : // KP7 + mplayer_put_key(KEY_KP7); + fsFlags = 0; // Clear flags + break; + + case 0x48 : // KP8 + mplayer_put_key(KEY_KP8); + fsFlags = 0; // Clear flags + break; + + case 0x49 : // KP9 + mplayer_put_key(KEY_KP9); + fsFlags = 0; // Clear flags + break; + + case 0x53 : // KPDEC, KPDEL + mplayer_put_key(usCh == '.' ? KEY_KPDEC : KEY_KPDEL); + fsFlags = 0; // Clear flags + break; + + case 0X5A : // KPENTER + mplayer_put_key(KEY_KPENTER); + fsFlags = 0; // Clear flags + break; + } + } + + if (fsFlags & KC_VIRTUALKEY) { + switch (usVk) { + case VK_LEFT : + mplayer_put_key(KEY_LEFT); + break; + + case VK_UP : + mplayer_put_key(KEY_UP); + break; + + case VK_RIGHT : + mplayer_put_key(KEY_RIGHT); + break; + + case VK_DOWN : + mplayer_put_key(KEY_DOWN); + break; + + case VK_TAB : + mplayer_put_key(KEY_TAB); + break; + + case VK_BACKSPACE : + mplayer_put_key(KEY_BS); + break; + + case VK_DELETE : + mplayer_put_key(KEY_DELETE); + break; + + case VK_INSERT : + mplayer_put_key(KEY_INSERT); + break; + + case VK_HOME : + mplayer_put_key(KEY_HOME); + break; + + case VK_END : + mplayer_put_key(KEY_END); + break; + + case VK_PAGEUP : + mplayer_put_key(KEY_PAGE_UP); + break; + + case VK_PAGEDOWN : + mplayer_put_key(KEY_PAGE_DOWN); + break; + + case VK_ESC : + mplayer_put_key(KEY_ESC); + break; + + case VK_SPACE : + mplayer_put_key(' '); + break; + + case VK_NEWLINE : + mplayer_put_key(KEY_ENTER); + break; + } + } + else if ((fsFlags & KC_CHAR) && !HIBYTE(usCh)) + mplayer_put_key(usCh); + + MRETURN(TRUE); + } + + case WM_BUTTON1DOWN : + if (WinQueryFocus(HWND_DESKTOP) != hwnd) + WinSetFocus(HWND_DESKTOP, hwnd); + else if (!vo_nomouse_input) + mplayer_put_key(MOUSE_BTN0); + + MRETURN(TRUE); + + case WM_BUTTON3DOWN : + if (WinQueryFocus(HWND_DESKTOP) != hwnd) + WinSetFocus(HWND_DESKTOP, hwnd); + else if (!vo_nomouse_input) + mplayer_put_key(MOUSE_BTN1); + + MRETURN(TRUE); + + case WM_BUTTON2DOWN : + if (WinQueryFocus(HWND_DESKTOP) != hwnd) + WinSetFocus(HWND_DESKTOP, hwnd); + else if (!vo_nomouse_input) + mplayer_put_key(MOUSE_BTN2); + + MRETURN(TRUE); + + case WM_BUTTON1DBLCLK : + if (!vo_nomouse_input) + mplayer_put_key(MOUSE_BTN0_DBL); + + MRETURN(TRUE); + + case WM_BUTTON3DBLCLK : + if (!vo_nomouse_input) + mplayer_put_key(MOUSE_BTN1_DBL); + + MRETURN(TRUE); + + case WM_BUTTON2DBLCLK : + if (!vo_nomouse_input) + mplayer_put_key(MOUSE_BTN2_DBL); + + MRETURN(TRUE); + + case WM_PAINT : + { + HPS hps; + RECTL rcl, rclDst; + PRECTL prcl = NULL; + HRGN hrgn, hrgnDst; + RGNRECT rgnCtl; + + kvaAdjustDstRect(&m_int.kvas.rclSrcRect, &rclDst); + + hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl); + + hrgn = GpiCreateRegion(hps, 1, &rcl); + hrgnDst = GpiCreateRegion(hps, 1, &rclDst); + + GpiCombineRegion(hps, hrgn, hrgn, hrgnDst, CRGN_DIFF); + + 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); + } + + 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); + + MRETURN(0); + } + } + + MRETURN(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; + + opt_t subopts[] = { + {"snap", OPT_ARG_BOOL, &fUseSnap, NULL, 0}, + {"wo", OPT_ARG_BOOL, &fUseWO, NULL, 0}, + {"dive", OPT_ARG_BOOL, &fUseDive, NULL, 0}, + {"t23", OPT_ARG_BOOL, &fFixT23, NULL, 0}, + {NULL, 0, NULL, NULL, 0} + }; + + PSZ pszVideoModeStr[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) + 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 & 0xFFFFFF)) { + 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", + pszVideoModeStr[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(); + + switch (format) { + case IMGFMT_YV12 : + m_int.fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YV12; + m_int.fcc = FOURCC_YV12; + m_int.bpp = 1; + break; + + case IMGFMT_YUY2 : + m_int.fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YUY2; + m_int.fcc = FOURCC_Y422; + m_int.bpp = 2; + break; + + case IMGFMT_YVU9 : + m_int.fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YVU9; + m_int.fcc = FOURCC_YVU9; + m_int.bpp = 1; + break; + + case IMGFMT_BGR24 : + m_int.fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR24; + m_int.fcc = FOURCC_BGR3; + m_int.bpp = 3; + break; + + case IMGFMT_BGR16 : + m_int.fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR16; + m_int.fcc = FOURCC_R565; + m_int.bpp = 2; + break; + + case IMGFMT_BGR15 : + m_int.fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR15; + m_int.fcc = FOURCC_R555; + m_int.bpp = 2; + break; + + default : + 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) { + m_int.fcc = FOURCC_YV12; + dstFormat = IMGFMT_YV12; + } else if (m_int.kvac.ulInputFormatFlags & KVAF_YUY2) { + m_int.fcc = FOURCC_Y422; + dstFormat = IMGFMT_YUY2; + } else if (m_int.kvac.ulInputFormatFlags & KVAF_YVU9) { + m_int.fcc = FOURCC_YVU9; + dstFormat = IMGFMT_YVU9; + } else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR24) { + m_int.fcc = FOURCC_BGR3; + dstFormat = IMGFMT_BGR24; + } else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR16) { + m_int.fcc = FOURCC_R565; + dstFormat = IMGFMT_BGR16; + } else if (m_int.kvac.ulInputFormatFlags & KVAF_BGR15) { + m_int.fcc = FOURCC_R555; + dstFormat = IMGFMT_BGR15; + } + + 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); + + if (!d_width) + d_width = width; + + if (!d_height) + d_height = height; + + 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); + + SET_ASPECT_RATIO(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 (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; +} + +static uint32_t put_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; + + if (mpi->flags & MP_IMGFLAG_PLANAR) + draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, mpi->x, mpi->y); + else + fast_memcpy(m_int.planes[0], mpi->planes[0], SRC_HEIGHT * m_int.stride[0]); + + return VO_TRUE; +} + +static int query_format(uint32_t format) +{ + BOOL fHWAccel; + int res; + + switch (format) { + case IMGFMT_YV12 : + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YV12; + break; + + case IMGFMT_YUY2 : + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YUY2; + break; + + case IMGFMT_YVU9 : + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_YVU9; + break; + + case IMGFMT_BGR24 : + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR24; + break; + + case IMGFMT_BGR16 : + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR16; + break; + + case IMGFMT_BGR15 : + fHWAccel = m_int.kvac.ulInputFormatFlags & KVAF_BGR15; + break; + + default : + 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; + + SET_ASPECT_RATIO(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; + + SET_ASPECT_RATIO(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 put_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[]) +{ + fast_memcpy(m_int.planes[0], src[0], SRC_HEIGHT * m_int.stride[0]); + + return 0; +} + +static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y) +{ + uint8_t *s; + uint8_t *d; + int n; + + n = m_int.iImageFormat == IMGFMT_YV12 ? 2 : 4; + + // copy Y + d = m_int.planes[0] + m_int.stride[0] * y + x; + s = src[0]; + mem2agpcpy_pic(d, s, w, h, m_int.stride[0], stride[0]); + + w /= n; h /= n; x /= n; y /= n; + + // 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); +} + + Index: configure =================================================================== --- configure (revision 28767) +++ configure (working copy) @@ -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 (SNAP/WarpOverlay!/DIVE) video output [autodetect] --enable-aa enable AAlib video output [autodetect] --enable-caca enable CACA video output [autodetect] --enable-ggi enable GGI video output [autodetect] @@ -555,6 +557,7 @@ _xvmc=no #auto when complete _vdpau=auto _sdl=auto +_kva=auto _direct3d=auto _directx=auto _win32waveout=auto @@ -886,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 ;; @@ -5091,6 +5099,30 @@ echores "$_sdl" +if os2 ; then +echocheck "KVA (SNAP/WarpOverlay!/DIVE)" +if test "$_kva" = auto; then + cat > $TMPC << EOF +#include +#include +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" + _vosrc="$_vosrc vo_kva.c" + _vomodules="kva $_vomodules" +else + def_kva='#undef CONFIG_KVA' + _novomodules="kva $_novomodules" +fi +echores "$_kva" +fi #if os2 + + if win32; then echocheck "Windows waveout" @@ -8116,6 +8173,7 @@ JACK = $_jack JOYSTICK = $_joystick JPEG = $_jpeg +KVA = $_kva LADSPA = $_ladspa LIBA52 = $_liba52 LIBA52_INTERNAL = $_liba52_internal @@ -8617,6 +8676,7 @@ $def_gl_win32 $def_ivtv $def_jpeg +$def_kva $def_md5sum $def_mga $def_mng Index: DOCS/man/en/mplayer.1 =================================================================== --- DOCS/man/en/mplayer.1 (revision 28767) +++ DOCS/man/en/mplayer.1 (working copy) @@ -3573,6 +3585,22 @@ .PD 1 . .TP +.B kva (OS/2 only) +Video output driver that uses the libkva interface. +.PD 0 +.RSs +.IPs snap +Use SNAP mode. +.IPs wo +Use WarpOverlay! mode. +.IPs dive +Use DIVE mode. +.IPs (no)t23 +Enable/disable workaround for T23 laptop (default: \-not23). +.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 Index: Changelog =================================================================== --- Changelog (revision 28767) +++ Changelog (working copy) @@ -99,6 +99,7 @@ * factorize code in vo_wii * removed unnecessary code from vo x11, xv, xvmc * automatic detection of hw acceleration (vo gl:yuv=x) for vo_gl + * add OS/2 KVA video driver (-vo kva) MEncoder: * check for system-wide configuration file in MEncoder