/* * 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 "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 ", "" }; const 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 mp_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 mp_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 mp_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[MP_MAX_PLANES]; // y = 0, u = 1, v = 2 int stride[MP_MAX_PLANES]; BOOL fHWAccel; RECTL rclParent; struct SwsContext *sws; } m_int; static inline void setAspectRatio(ULONG ulRatio) { ULONG ulValue; int i; m_int.kvas.ulRatio = ulRatio; kvaSetup(&m_int.kvas); // Setup initializes all attributes, so need to restore them. for (i = 0; i < KVAA_LAST; i++) { kvaQueryAttr(i, &ulValue); kvaSetAttr(i, &ulValue); } } 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); memset(m_int.planes, 0, sizeof(m_int.planes)); memset(m_int.stride, 0, sizeof(m_int.stride)); 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[MP_MAX_PLANES] = {NULL}; int dstStride[MP_MAX_PLANES] = {0}; // 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 { ULONG ulStyle; hwndParent = HWNDFROMWINID(WinID); flFrameFlags = 0; // Prevent a parent window from painting over our window ulStyle = WinQueryWindowULong(hwndParent, QWL_STYLE); WinSetWindowULong(hwndParent, QWL_STYLE, ulStyle | WS_CLIPCHILDREN); } 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: { struct voctrl_set_equalizer_args *args = data; color_ctrl_set(args->name, args->value); } case VOCTRL_GET_EQUALIZER: { struct voctrl_get_equalizer_args *args = data; return color_ctrl_get(args->name, args->valueptr); } 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); }