Index: AUTHORS =================================================================== --- AUTHORS (revision 27905) +++ AUTHORS (working copy) @@ -732,6 +732,9 @@ * nvidia_vid VIDIX driver * dhahelperwin for direct hardware access under Windows NT/2000/XP +Petrov, Georgi + * Direct3D VO driver + Stepanov, Evgeniy (eugeni, Azzy) * SSA/ASS subtitle renderer * Matroska chapter seeking Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 0) +++ libvo/vo_direct3d.c (revision 0) @@ -0,0 +1,1005 @@ +/* + * vo_direct3d.c: Experimental Direct3D 9 driver + * Last modified: 13.11.2008, Version 0.0.3 + * + * Copyright (c) 2008 Georgi Petrov (gogothebee) + * + * 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. + */ + +#include +#include +#include +#include +#include "config.h" +#include "video_out.h" +#include "video_out_internal.h" +#include "fastmemcpy.h" +#include "mp_msg.h" +#include "input/mouse.h" +#include "input/input.h" +#include "osdep/keycodes.h" +#include "mp_fifo.h" + +#ifndef WM_XBUTTONDOWN +# define WM_XBUTTONDOWN 0x020B +# define WM_XBUTTONUP 0x020C +# define WM_XBUTTONDBLCLK 0x020D +#endif + +#define WINDOW_TITLE_SIZE 64 + +static const vo_info_t info = +{ + "Direct3D 9 Experimental Renderer", + "direct3d", + "Georgi Petrov ", + "" +}; + +/* + * Link essential libvo functions: preinit, config, control, draw_frame, + * draw_slice, draw_osd, flip_page, check_events, uninit and + * the strcuture info. Only there functions are essential for libvo. + */ +const LIBVO_EXTERN(direct3d) + + +/* + * Function declarations + */ + +static LRESULT CALLBACK MsgProc (HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam); +int D3DConfigure (void); + +/* + * Global config variables. Every global variable is + * defined in gConfig to make the difference easier. + * I try to keep their count low. + */ + +static struct stD3DConfig +{ + WNDCLASSEX WindowClass; /**< Onscreen window class */ + HWND WindowHandle; /**< Onscreen window handle */ + char WindowTitle[WINDOW_TITLE_SIZE]; /**< Onscreen window title */ + + RECT CurrentRect; /**< External rectangle of the now-playing + window in windowed mode */ + RECT FullScrMovieRect; /**< Fullscreen MOVIE RECT. This means width + stretched movie with centered height + which the user sees in fullscreen */ + BOOL IsFullScreen; /**< Toogle FullScreen */ + BOOL IsD3DInitialized; /**< TRUE = Direct3D context is present in + the window, FALSE = it's not */ + BOOL IsD3DConfigFinished; /**< Synchronization "semaphore". TRUE when + instance of D3DConfigure is finished */ + int SrcWidth; /**< Source (movie) width */ + int SrcHeight; /**< Source (movie) heigth */ + int DstWidth; /**< Destination (screen) width */ + int DstHeight; /**< Destination (screen) height */ + float AspectRatio; /**< Movie aspect ratio. Used to calculate + scaling while preserving aspect ratio */ + + LPDIRECT3D9 pD3DHandle; /**< Direct3D Handle */ + LPDIRECT3DDEVICE9 pD3DDevice; /**< The Direct3D Adapter */ + IDirect3DSurface9 *pD3DSurface; /**< Offscreen Direct3D Surface. MPlayer + renders inside it. Uses colorspace + MovieSrcFmt */ + IDirect3DSurface9 *pD3DBackBuf; /**< Video card's back buffer (used to + display next frame) */ + D3DFORMAT MovieSrcFmt; /**< Movie colorspace format (depends on + the movie's codec) */ + D3DFORMAT DesktopFmt; /**< Desktop (screen) colorspace format. + Usually XRGB */ +} gConfig; + +typedef struct +{ + const unsigned int MPlayerFormat; /**< Given by Mplayer */ + const D3DFORMAT FourCC; /**< Required by D3D's test function */ +} ColorSpaceTable; + +/* Map table from reported MPlayer format to the required + FourCC. This is needed to perform the format query */ + +static const ColorSpaceTable gColorSpaceTable[] = +{ + {IMGFMT_YV12, MAKEFOURCC('Y','V','1','2')}, + {IMGFMT_I420, MAKEFOURCC('I','4','2','0')}, + {IMGFMT_IYUV, MAKEFOURCC('I','Y','U','V')}, + {IMGFMT_YVU9, MAKEFOURCC('Y','V','U','9')}, + {IMGFMT_YUY2, MAKEFOURCC('Y','U','Y','2')}, + {IMGFMT_UYVY, MAKEFOURCC('U','Y','V','Y')} +}; + +#define COLOR_SPACE_TABLE_ENTRIES \ + (sizeof(gColorSpaceTable) / sizeof(gColorSpaceTable[0])) + +/**************************************************************************** + * * + * * + * * + * Direct3D specific implementation functions * + * * + * * + * * + ****************************************************************************/ + +/** @brief Destroy D3D Context related to the current window + * @return TRUE on success, FALSE on failure + */ +void D3DDestroyContext (void) +{ + mp_msg(MSGT_VO,MSGL_ERR,"D3DDestroyContext called\r\n"); + /* Let's destroy the old (if any) D3D Content */ + + if (gConfig.pD3DSurface != NULL) + { + IDirect3DSurface9_Release (gConfig.pD3DSurface); + gConfig.pD3DSurface = NULL; + } + + if (gConfig.pD3DDevice != NULL) + { + IDirect3DDevice9_Release (gConfig.pD3DDevice); + gConfig.pD3DDevice = NULL; + } + + /* The following is not a memory leak. pD3DBackBuf is not malloc'ed + * but just holds a pointer to the back buffer. Nobody gets hurt from + * setting it to NULL. + */ + gConfig.pD3DBackBuf = NULL; +} + + +/** @brief (Re)Create MPlayer Window on the screen + * @return TRUE on success, FALSE on failure + */ +int CreateWindowOnScreen (void) +{ + WINDOWINFO NewWindow; + RECT FullScreenRect; /** External (not client) coordinates of the + * fullscreen window */ + int CalculatedHeight; /** Calculated fullscreen movie height. It's + * relative to the new + * width while observing correct aspect ratio */ + memset(&NewWindow, 0, sizeof(WINDOWINFO)); + + /* Create the application's window. Depending from what do we need, + * windowed or fullscreen mode is selected. + */ + + if (FALSE == gConfig.IsFullScreen) + { + /* Create windowed (not fullscreen) window */ + gConfig.WindowHandle = CreateWindow ("MPlayerClass", + gConfig.WindowTitle, WS_OVERLAPPEDWINDOW, + gConfig.CurrentRect.left, gConfig.CurrentRect.top, + gConfig.CurrentRect.right-gConfig.CurrentRect.left, + gConfig.CurrentRect.bottom-gConfig.CurrentRect.top, + NULL, NULL, gConfig.WindowClass.hInstance, NULL ); + } + else + { + /* Create fullscreen window */ + FullScreenRect.left = 0; + FullScreenRect.top = 0; + FullScreenRect.right = GetSystemMetrics(SM_CXSCREEN); + FullScreenRect.bottom = GetSystemMetrics(SM_CYSCREEN); + + /* We want client area of width/height, but CreateWindow wants window + * area - this means external coordinates of the window, which + * include the borders and title coordinates. AdjustWindowRect + * compensates and "expands" the RECT coordinates to produce suitable + * parameters for CreateWindow + */ + + AdjustWindowRect (&FullScreenRect, WS_POPUP | WS_SYSMENU + | WS_VISIBLE, FALSE); + mp_msg(MSGT_VO,MSGL_ERR,"FullScreen Monitor: right %ld, bottom %ld\n", + FullScreenRect.right, FullScreenRect.bottom); + + gConfig.WindowHandle = CreateWindow ("MPlayerClass", + gConfig.WindowTitle, WS_POPUP | WS_SYSMENU + | WS_VISIBLE, + FullScreenRect.left, FullScreenRect.top, + FullScreenRect.right-FullScreenRect.left, + FullScreenRect.bottom-FullScreenRect.top, + NULL, NULL, gConfig.WindowClass.hInstance, NULL); + + /* Center the movie realtive to it's height */ + + gConfig.FullScrMovieRect.left=0; + gConfig.FullScrMovieRect.right = FullScreenRect.right; + CalculatedHeight = + gConfig.FullScrMovieRect.right / gConfig.AspectRatio; + gConfig.FullScrMovieRect.top = + ((FullScreenRect.bottom - CalculatedHeight) / 2) /*- 1*/; + gConfig.FullScrMovieRect.bottom = + gConfig.FullScrMovieRect.top + CalculatedHeight; + + mp_msg(MSGT_VO,MSGL_ERR, + "Fullscreen MOVIE Rect: %ld, %ld, %ld, %ld, Calc: %d\n", + gConfig.FullScrMovieRect.left, gConfig.FullScrMovieRect.top, + gConfig.FullScrMovieRect.right, gConfig.FullScrMovieRect.bottom, + CalculatedHeight); + } + + if (NULL == gConfig.WindowHandle) + return FALSE; + + NewWindow.cbSize = sizeof(WINDOWINFO); + if (0 == GetWindowInfo (gConfig.WindowHandle, &NewWindow)) + { + /* Failed to get current window information */ + return FALSE; + } + + mp_msg(MSGT_VO,MSGL_ERR, + "Created window, CL width: %ld, height: %ld\n", + NewWindow.rcClient.right - NewWindow.rcClient.left, + NewWindow.rcClient.bottom - NewWindow.rcClient.top); + + ShowWindow (gConfig.WindowHandle, SW_SHOWDEFAULT); + UpdateWindow (gConfig.WindowHandle); + return TRUE; +} + +/** @brief (Re)Initialize Direct3D. Kill and recreate context. + * @param NewWindow The new Window's coordinates used to + * create D3D context + * @return TRUE on success, FALSE on failure + */ +int D3DRecreateContext(void) +{ + D3DPRESENT_PARAMETERS PresentParams; + D3DDISPLAYMODE DisplayMode; + WINDOWINFO NewWindow; + memset(&NewWindow, 0, sizeof(WINDOWINFO)); + + NewWindow.cbSize = sizeof(WINDOWINFO); + if (0 == GetWindowInfo (gConfig.WindowHandle, &NewWindow)) + return FALSE; + + /* Copy new window's coordinates only if we're not in fullscreen. + * Otherwise we will copy fullscreen's window coordinates over + * windowed one's. + */ + if (FALSE == gConfig.IsFullScreen) + { + gConfig.DstWidth = + NewWindow.rcClient.right - NewWindow.rcClient.left; + gConfig.DstHeight = + NewWindow.rcClient.bottom - NewWindow.rcClient.top; + + gConfig.CurrentRect.top = NewWindow.rcWindow.top; + gConfig.CurrentRect.bottom = NewWindow.rcWindow.bottom; + gConfig.CurrentRect.left = NewWindow.rcWindow.left; + gConfig.CurrentRect.right = NewWindow.rcWindow.right; + } + + D3DDestroyContext(); + + /* Get the current desktop display mode, so we can set up a back buffer + * of the same format */ + if (FAILED (IDirect3D9_GetAdapterDisplayMode (gConfig.pD3DHandle, + D3DADAPTER_DEFAULT, + &DisplayMode))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "Could not read adapter display mode.\n"); + return FALSE; + } + + /* Write current Desktop's colorspace format in the global storage */ + gConfig.DesktopFmt = DisplayMode.Format; + + /* Prepare Direct3D initialization parameters */ + memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS)); + PresentParams.Windowed = TRUE; + PresentParams.SwapEffect = D3DSWAPEFFECT_COPY; + PresentParams.Flags = D3DPRESENTFLAG_VIDEO; + PresentParams.hDeviceWindow = gConfig.WindowHandle; + PresentParams.BackBufferWidth = 0; /* Fill up window Width */ + PresentParams.BackBufferHeight = 0; /* Fill up window Height */ + PresentParams.MultiSampleType = D3DMULTISAMPLE_NONE; + /* D3DPRESENT_INTERVAL_ONE = vsync */ + PresentParams.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + PresentParams.BackBufferFormat = gConfig.DesktopFmt; + PresentParams.BackBufferCount = 1; + PresentParams.EnableAutoDepthStencil = FALSE; + + if (FAILED (IDirect3D9_CreateDevice(gConfig.pD3DHandle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, gConfig.WindowHandle, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + /* D3DDEVCAPS HWTRANSFORMANDLIGHT */ + &PresentParams, &gConfig.pD3DDevice))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "Could not create the D3D device\n"); + return FALSE; + } + + mp_msg(MSGT_VO,MSGL_ERR, + "New BackBuffer: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", + PresentParams.BackBufferWidth, PresentParams.BackBufferHeight, + gConfig.DstWidth, gConfig.DstHeight); + + if (FAILED (IDirect3DDevice9_CreateOffscreenPlainSurface( + gConfig.pD3DDevice, gConfig.SrcWidth, gConfig.SrcHeight, + gConfig.MovieSrcFmt, D3DPOOL_DEFAULT, &gConfig.pD3DSurface, NULL))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); + return FALSE; + } + + if (FAILED (IDirect3DDevice9_GetBackBuffer (gConfig.pD3DDevice, 0, 0, + D3DBACKBUFFER_TYPE_MONO, + &(gConfig.pD3DBackBuf)))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Back Buffer address get failed\n"); + return FALSE; + } + + /* Fill the Surface with black color */ + IDirect3DDevice9_ColorFill(gConfig.pD3DDevice, gConfig.pD3DSurface, NULL, + D3DCOLOR_ARGB(0xFF, 0, 0, 0) ); + + gConfig.IsD3DInitialized = TRUE; + return TRUE; +} + +/** @brief Switch between Fullscreen and windowed mode + * @return N/A + */ +void ToogleFullscreen(void) +{ + mp_msg(MSGT_VO,MSGL_ERR,"ToogleFullscreen called\r\n"); + if (FALSE == gConfig.IsFullScreen) + gConfig.IsFullScreen = TRUE; + else + gConfig.IsFullScreen = FALSE; + + D3DDestroyContext(); + if (NULL != gConfig.WindowHandle) + { + if (0 != DestroyWindow (gConfig.WindowHandle)) + mp_msg(MSGT_VO,MSGL_ERR,"Window destroyed\r\n"); + else + mp_msg(MSGT_VO,MSGL_ERR,"Can't destroy the Window\r\n"); + } + /* Set WindowHandle to NULL, because CreateWindowOnScreen checks it as + * a sign that there is no window currently on the screen. + * Inform D3DConfig() that D3D is not initialized. */ + gConfig.WindowHandle = NULL; + gConfig.IsD3DInitialized = FALSE; + + /* CreateWindowOnScreen will observe gConfig.IsFullScreen and create + * fullscreen or windowed window according to the variable. Afterward + * it will create D3D context inside with the new dimensions. + */ + if (gConfig.IsD3DConfigFinished == TRUE) + { + gConfig.IsD3DConfigFinished = FALSE; + D3DConfigure (); + gConfig.IsD3DConfigFinished = TRUE; + } +} + +/** @brief Initialize window with D3D context inside + * @return TRUE on success, FALSE on failure + * The first function called to init D3D context. + */ +int D3DConfigure (void) +{ + mp_msg(MSGT_VO,MSGL_ERR,"D3DConfigure CALLED\n"); + + /* Create new window on the screen. This is necessary if this is the + * first call to this function ever or we just destroyed the old window + * context after fullscreen toogle. + */ + if (NULL == gConfig.WindowHandle) + { + if (FALSE == CreateWindowOnScreen ()) + return FALSE; + gConfig.IsD3DInitialized = FALSE; + } + + if (TRUE == gConfig.IsD3DInitialized) + return TRUE; + + if (FALSE == D3DRecreateContext()) + return FALSE; + + return TRUE; +} + +/** @brief Shutdown Direct3D and close the window + * @return N/A + */ +void D3DUninit(void) +{ + mp_msg(MSGT_VO,MSGL_ERR,"D3DUninit called\r\n"); + + /* Block further calls to D3DConfigure() */ + gConfig.IsD3DConfigFinished = FALSE; + + /* Destroy D3D Context inside the window */ + D3DDestroyContext(); + + /* Stop the whole D3D */ + if (NULL != gConfig.pD3DHandle) + { + mp_msg(MSGT_VO,MSGL_ERR,"Calling IDirect3D9_Release\r\n"); + IDirect3D9_Release (gConfig.pD3DHandle); + } + + /* Destroy the window */ + if (NULL != gConfig.WindowHandle) + { + if (0 != DestroyWindow (gConfig.WindowHandle)) + mp_msg(MSGT_VO,MSGL_ERR,"Window destroyed\r\n"); + else + mp_msg(MSGT_VO,MSGL_ERR,"Can't destroy the Window\r\n"); + } + + /* Unregister MPlayerClass */ + if (0 != UnregisterClass("MPlayerClass", GetModuleHandle(NULL))) + mp_msg(MSGT_VO,MSGL_ERR,"Window Class destroyed\r\n"); + else + mp_msg(MSGT_VO,MSGL_ERR,"Can't destroy the Wind Class\r\n"); + return; +} + +/** @brief Process Window Messages + * @return + */ +static LRESULT CALLBACK MsgProc (HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_MOUSEACTIVATE: + return MA_ACTIVATEANDEAT; + break; + case WM_NCACTIVATE: + break; + case WM_DESTROY: + PostQuitMessage(0); + return 0; + break; + case WM_CLOSE: + mplayer_put_key(KEY_CLOSE_WIN); + return 0; + break; + case WM_SYSCOMMAND: + switch (wParam) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + mp_msg(MSGT_VO, MSGL_ERR ,"killing the screensaver\n" ); + return 0; + case SC_MAXIMIZE: + if (gConfig.IsFullScreen == FALSE) + control(VOCTRL_FULLSCREEN, NULL); + return 0; + } + break; + case WM_KEYDOWN: + switch (wParam) + { + 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_BACK: + {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_PRIOR: + {mplayer_put_key(KEY_PAGE_UP);break;} + case VK_NEXT: + {mplayer_put_key(KEY_PAGE_DOWN);break;} + case VK_ESCAPE: + {mplayer_put_key(KEY_ESC);break;} + } + break; + case WM_CHAR: + mplayer_put_key(wParam); + break; + case WM_LBUTTONDOWN: + mplayer_put_key(MOUSE_BTN0); + break; + case WM_MBUTTONDOWN: + mplayer_put_key(MOUSE_BTN1); + break; + case WM_RBUTTONDOWN: + mplayer_put_key(MOUSE_BTN2); + break; + case WM_LBUTTONDBLCLK: + mplayer_put_key(MOUSE_BTN0_DBL); + break; + case WM_MBUTTONDBLCLK: + mplayer_put_key(MOUSE_BTN1_DBL); + break; + case WM_RBUTTONDBLCLK: + mplayer_put_key(MOUSE_BTN2_DBL); + break; + case WM_MOUSEWHEEL: + if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) + mplayer_put_key(MOUSE_BTN3); + else + mplayer_put_key(MOUSE_BTN4); + break; + case WM_XBUTTONDOWN: + if (HIWORD(wParam) == 1) + mplayer_put_key(MOUSE_BTN5); + else + mplayer_put_key(MOUSE_BTN6); + break; + case WM_XBUTTONDBLCLK: + if (HIWORD(wParam) == 1) + mplayer_put_key(MOUSE_BTN5_DBL); + else + mplayer_put_key(MOUSE_BTN6_DBL); + break; + case WM_SIZE: + mp_msg(MSGT_VO,MSGL_ERR,"WM_SIZE\n"); + if (TRUE == gConfig.IsD3DInitialized && + gConfig.IsD3DConfigFinished == TRUE) + { + gConfig.IsD3DConfigFinished = FALSE; + /* Force recreation of the D3D Context */ + gConfig.IsD3DInitialized = FALSE; + D3DConfigure (); + gConfig.IsD3DConfigFinished = TRUE; + } + return 0; + break; + + } + return DefWindowProc(hWnd, message, wParam, lParam); +} + +/** @brief Render a frame on the screen + * @param mpi Mpi structure with the decoded frame inside + * @return 0 on success, VO_ERROR on failure + */ +static uint32_t D3DRenderFrame (mp_image_t *mpi) +{ + D3DLOCKED_RECT stLockedRect; /**< Offscreen surface we lock in order + to copy MPlayer's frame inside it.*/ + if((mpi->flags & MP_IMGFLAG_DIRECT) || + (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) + { + mp_msg(MSGT_VO, MSGL_ERR ,"Something went wrong\n"); + return VO_ERROR; + } + + if (FAILED (IDirect3DSurface9_LockRect(gConfig.pD3DSurface, + &stLockedRect, NULL, 0))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Surface lock failure\n"); + return VO_FALSE; + } + + if (mpi->flags & MP_IMGFLAG_PLANAR) + { /* Copy a planar frame */ + + /* Copy Y */ + memcpy_pic(stLockedRect.pBits, mpi->planes[0], mpi->stride[0], + mpi->height, stLockedRect.Pitch, mpi->stride[0]); + + /* Copy V. Casting to char * is here to suppress a compiler warning. */ + memcpy_pic((char *)stLockedRect.pBits + stLockedRect.Pitch * + mpi->height, mpi->planes[2], mpi->stride[2], mpi->height / 2, + stLockedRect.Pitch / 2, mpi->stride[2]); + + /* Copy U. Casting to char * is here to suppress a compiler warning. */ + memcpy_pic((char *)stLockedRect.pBits + stLockedRect.Pitch * + mpi->height + (stLockedRect.Pitch * mpi->height) / 4, + mpi->planes[1], mpi->stride[1], mpi->height / 2, + stLockedRect.Pitch / 2, mpi->stride[1]); + } + else + { /* Copy a packed frame */ + memcpy_pic(stLockedRect.pBits, mpi->planes[0], mpi->stride[0], + mpi->height, stLockedRect.Pitch, mpi->stride[0]); + } + + + if (FAILED (IDirect3DSurface9_UnlockRect(gConfig.pD3DSurface))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Surface unlock failure\n"); + return VO_ERROR; + } + + if (FAILED (IDirect3DDevice9_StretchRect (gConfig.pD3DDevice, + gConfig.pD3DSurface,NULL, + gConfig.pD3DBackBuf, + TRUE == gConfig.IsFullScreen ? + &gConfig.FullScrMovieRect : NULL, + D3DTEXF_LINEAR))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "Unable to copy the frame to the back buffer\n"); + return VO_ERROR; + } + + return 0; /* Success */ +} + + +/** @brief Query if movie's colorspace is supported by the HW + * @return 0 on failure, device capabilities (not probed + * currently) on success. + */ +static int query_format (uint32_t MovieFormat) +{ + int i; + for (i=0; i < COLOR_SPACE_TABLE_ENTRIES; i++) + { + if (gColorSpaceTable[i].MPlayerFormat == MovieFormat) + { + /* Test conversion from Movie colorspace to + * display's target colorspace*/ + if (FAILED (IDirect3D9_CheckDeviceFormatConversion( + gConfig.pD3DHandle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + gColorSpaceTable[i].FourCC, + gConfig.DesktopFmt))) + return 0; + + gConfig.MovieSrcFmt = gColorSpaceTable[i].FourCC; + mp_msg(MSGT_VO,MSGL_ERR,"Accepted Colorspace %s\n", + vo_format_name(gColorSpaceTable[i].MPlayerFormat)); + return (VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW + /*| VFCAP_OSD*/ | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN); + + } + } + + return 0; +} + +/**************************************************************************** + * * + * * + * * + * libvo Control / Callback functions * + * * + * * + * * + ****************************************************************************/ + + + + +/** @brief libvo Callback: Preinitialize the Video card + * @return TRUE on success, FALSE on failure + * + * Preinit the HW just enough to be queried about supported + * formats. + */ +static int preinit(const char *arg) +{ + D3DDISPLAYMODE DisplayMode; + + /* Clear gConfig, the global storage container. */ + memset(&gConfig, 0, sizeof(gConfig)); + + /* FIXME + > Please use subopt-helper.h for this, see vo_gl.c:preinit for + > an example of how to use it. + */ + + if (NULL == (gConfig.pD3DHandle = Direct3DCreate9 (D3D_SDK_VERSION))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Unable to initialize Direct3D\n"); + return -1; + } + + if (FAILED (IDirect3D9_GetAdapterDisplayMode (gConfig.pD3DHandle, + D3DADAPTER_DEFAULT, + &DisplayMode))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Could not read display mode\n"); + return -1; + } + + /* Store in DesktopFmt the user desktop's colorspace. Usually XRGB */ + gConfig.DesktopFmt = DisplayMode.Format; + + mp_msg(MSGT_VO,MSGL_ERR,"DisplayMode.Width %d, DisplayMode.Height %d\n", + DisplayMode.Width, DisplayMode.Height); + + + /* Register the window class */ + gConfig.WindowClass.cbSize = sizeof(WNDCLASSEX); + gConfig.WindowClass.style = CS_CLASSDC; + gConfig.WindowClass.lpfnWndProc = MsgProc; + gConfig.WindowClass.cbClsExtra = 0; + gConfig.WindowClass.cbWndExtra = 0; + gConfig.WindowClass.hInstance = GetModuleHandle(NULL); + gConfig.WindowClass.hIcon = NULL; + gConfig.WindowClass.hCursor = NULL; + gConfig.WindowClass.hbrBackground = NULL; + gConfig.WindowClass.lpszMenuName = NULL; + gConfig.WindowClass.lpszClassName = "MPlayerClass"; + gConfig.WindowClass.hIconSm = NULL; + RegisterClassEx (&gConfig.WindowClass); + + /* Allow the first call to D3DConfigure */ + gConfig.IsD3DConfigFinished = TRUE; + + return 0; +} + + + +/** @brief libvo Callback: Handle control requests + * @return VO_TRUE on success, VO_NOTIMPL when not + * implemented + */ +static int control(uint32_t request, void *data, ...) +{ + switch (request) + { + case VOCTRL_QUERY_FORMAT: + return query_format (*(uint32_t*) data); + case VOCTRL_GET_IMAGE: /* Direct Rendering. Not implemented yet */ + mp_msg(MSGT_VO,MSGL_ERR, + "Direct Rendering request. Not implemented yet\n"); + return VO_NOTIMPL; + case VOCTRL_DRAW_IMAGE: + D3DRenderFrame (data); + return VO_TRUE; + case VOCTRL_FULLSCREEN: + ToogleFullscreen(); + return VO_TRUE; + case VOCTRL_RESET: + return VO_NOTIMPL; + case VOCTRL_PAUSE: + return VO_NOTIMPL; + case VOCTRL_RESUME: + return VO_NOTIMPL; + case VOCTRL_GUISUPPORT: + return VO_NOTIMPL; + case VOCTRL_SET_EQUALIZER: + return VO_NOTIMPL; + case VOCTRL_GET_EQUALIZER: + return VO_NOTIMPL; + case VOCTRL_ONTOP: + return VO_NOTIMPL; + case VOCTRL_BORDER: + return VO_NOTIMPL; + } + return VO_FALSE; +} + +/** @brief libvo Callback: Configre the Direct3D adapter + * @param width Movie source width + * @param height Movie source height + * @param d_width Screen (destination) width + * @param d_height Screen (destination) height + * @param options Options bitmap + * @param title Windows title + * @param format Movie colorspace format (using Mplayer's + * defines, e.g. IMGFMT_YUY2) + * @return 0 on success, VO_ERROR on failure + */ +static int config(uint32_t width, uint32_t height, uint32_t d_width, + uint32_t d_height, uint32_t options, char *title, + uint32_t format) +{ + /* GOGO FIXME: You should call geometry() in config() to enable user + * defined window size and position. */ + + gConfig.SrcWidth = width; + gConfig.SrcHeight = height; + gConfig.DstWidth = d_width; + gConfig.DstHeight = d_height; + + /* Let's just give some fixed x,y coordinates for the first window */ + gConfig.CurrentRect.top = 50; + gConfig.CurrentRect.left = 50; + gConfig.CurrentRect.right = gConfig.CurrentRect.left + gConfig.DstWidth; + gConfig.CurrentRect.bottom = gConfig.CurrentRect.top + gConfig.DstHeight; + + /* We want width:height of CLIENT AREA, but CreateWindow's parameters are + * the external (including borders and title) dimensions. So we call + * AdjustWindowRect and it expands our RECT with the right amount of extra + * pixels in each direction. This way we have our required client area. + */ + AdjustWindowRect (&gConfig.CurrentRect, WS_OVERLAPPEDWINDOW, FALSE); + + mp_msg(MSGT_VO,MSGL_ERR, + "config: SRC: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", + gConfig.SrcWidth, gConfig.SrcHeight,gConfig.DstWidth,gConfig.DstHeight); + + gConfig.IsFullScreen = options & VOFLAG_FULLSCREEN; + gConfig.AspectRatio = (float)d_width / (float)d_height; + + if (gConfig.IsD3DConfigFinished == TRUE) + { + gConfig.IsD3DConfigFinished = FALSE; + if (FALSE == D3DConfigure ()) + { + gConfig.IsD3DConfigFinished = TRUE; + return VO_ERROR; + } + gConfig.IsD3DConfigFinished = TRUE; + } + return 0; /* Success */ +} + +/** @brief libvo Callback: Flip next already drawn frame on the + * screen. + * @return N/A + */ +static void flip_page(void) +{ + if (FAILED (IDirect3DDevice9_Present (gConfig.pD3DDevice, 0, 0, 0, 0))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "Video adapter became uncooperative.\n"); + mp_msg(MSGT_VO,MSGL_ERR,"Trying to reinitialize it...\n"); + gConfig.IsD3DInitialized = FALSE; + if (FALSE == D3DConfigure()) + { + mp_msg(MSGT_VO,MSGL_ERR,"Reinitialization Failed.\n"); + return; + } + if (FAILED (IDirect3DDevice9_Present (gConfig.pD3DDevice, 0, 0, 0, 0))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Reinitialization Failed.\n"); + return; + } + else + mp_msg(MSGT_VO,MSGL_ERR,"Video adapter reinitialized.\n"); + + } +} + +/** @brief libvo Callback: Draw OSD/Subtitles + * @return N/A + */ +static void draw_osd(void) +{ +} + +/** @brief libvo Callback: Uninitializes all pointers and closes + * all D3D related stuff + * @return N/A + */ +static void uninit(void) +{ + D3DUninit(); + mp_msg(MSGT_VO,MSGL_ERR,"uninit called\r\n"); +} + +/** @brief libvo Callback: Handles video window events + * @return N/A + */ +static void check_events(void) +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +/** @brief libvo Callback: Unused function + * @return 0 on success + */ +static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y ) +{ + D3DLOCKED_RECT stLockedRect; /**< Offscreen surface we lock in order + to copy MPlayer's frame inside it.*/ + char *Src; /**< Pointer to the source image */ + char *Dst; /**< Pointer to the destination image */ + int UVstride; /**< Stride of the U/V planes */ + + if (FAILED (IDirect3DSurface9_LockRect(gConfig.pD3DSurface, + &stLockedRect, NULL, 0))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Surface lock failure\n"); + return VO_FALSE; + } + + UVstride = stLockedRect.Pitch / 2; + + /* Copy Y */ + Dst = (char *)stLockedRect.pBits + stLockedRect.Pitch * y + x; + Src=src[0]; + memcpy_pic(Dst, Src, w, h, stLockedRect.Pitch, stride[0]); + + w/=2;h/=2;x/=2;y/=2; + + /* Copy U. Casting to char * is here to suppress a compiler warning. */ + Dst = (char *)stLockedRect.pBits + stLockedRect.Pitch * gConfig.SrcHeight + + UVstride * y + x; + if (gConfig.MovieSrcFmt == MAKEFOURCC('Y','V','1','2')) + Src=src[2]; + else + Src=src[1]; + + memcpy_pic(Dst, Src, w, h, UVstride, stride[1]); + + /* Copy V. Casting to char * is here to suppress a compiler warning. */ + Dst = (char *)stLockedRect.pBits + stLockedRect.Pitch * gConfig.SrcHeight + + UVstride * (gConfig.SrcHeight / 2) + UVstride * y + x; + if (gConfig.MovieSrcFmt == MAKEFOURCC('Y','V','1','2')) + Src=src[1]; + else + Src=src[2]; + + memcpy_pic(Dst, Src, w, h, UVstride, stride[2]); + + if (FAILED (IDirect3DSurface9_UnlockRect(gConfig.pD3DSurface))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Surface unlock failure\n"); + return VO_ERROR; + } + + if (FAILED (IDirect3DDevice9_StretchRect (gConfig.pD3DDevice, + gConfig.pD3DSurface,NULL, + gConfig.pD3DBackBuf, + TRUE == gConfig.IsFullScreen ? + &gConfig.FullScrMovieRect : NULL, + D3DTEXF_LINEAR))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "Unable to copy the frame to the back buffer\n"); + return VO_ERROR; + } + + return 0; /* Success */ +} + +/** @brief libvo Callback: Unused function + * @return N/A + */ +static int draw_frame(uint8_t *src[]) +{ + mp_msg(MSGT_VO,MSGL_ERR,"draw_frame called\n"); + return VO_FALSE; +} + + + + Index: libvo/video_out.c =================================================================== --- libvo/video_out.c (revision 27905) +++ libvo/video_out.c (working copy) @@ -94,6 +94,7 @@ extern vo_functions_t video_out_mpegpes; extern vo_functions_t video_out_yuv4mpeg; extern vo_functions_t video_out_directx; +extern vo_functions_t video_out_direct3d; extern vo_functions_t video_out_dxr2; extern vo_functions_t video_out_dxr3; extern vo_functions_t video_out_ivtv; @@ -125,6 +126,9 @@ #ifdef CONFIG_DIRECTX &video_out_directx, #endif +#ifdef CONFIG_DIRECT3D + &video_out_direct3d, +#endif #ifdef CONFIG_COREVIDEO &video_out_macosx, #endif Index: configure =================================================================== --- configure (revision 27905) +++ configure (working copy) @@ -357,6 +357,7 @@ --enable-ggi enable GGI video output [autodetect] --enable-ggiwmh enable GGI libggiwmh extension [autodetect] --enable-directx enable DirectX video output [autodetect] + --enable-direct3d enable Direct3D video output [autodetect] --enable-dxr2 enable DXR2 video output [autodetect] --enable-dxr3 enable DXR3/H+ video output [autodetect] --enable-ivtv enable IVTV TV-Out video output [autodetect] @@ -533,6 +534,7 @@ _xvmc=no #auto when complete _sdl=auto _directx=auto +_direct3d=auto _win32waveout=auto _nas=auto _png=auto @@ -851,6 +853,8 @@ --disable-sdl) _sdl=no ;; --enable-directx) _directx=yes ;; --disable-directx) _directx=no ;; + --enable-direct3d) _direct3d=yes ;; + --disable-direct3d) _direct3d=no ;; --enable-win32waveout) _win32waveout=yes ;; --disable-win32waveout) _win32waveout=no ;; --enable-nas) _nas=yes ;; @@ -4873,6 +4877,28 @@ fi echores "$_directx" + +echocheck "Direct3D" +if test "$_direct3d" = auto ; then + cat > $TMPC << EOF +#include +#include +int main(void) { return 0; } +EOF + _direct3d=no + cc_check -ld3d9 && _direct3d=yes +fi +if test "$_direct3d" = yes ; then + _def_direct3d='#define CONFIG_DIRECT3D 1' + _libs_mplayer="$_libs_mplayer -ld3d9" + _vosrc="$_vosrc vo_direct3d.c" + _vomodules="direct3d $_vomodules" +else + _def_direct3d='#undef CONFIG_DIRECT3D' + _novomodules="direct3d $_novomodules" +fi +echores "$_direct3d" + fi #if win32; then @@ -8322,6 +8348,7 @@ $_def_directfb $_def_directfb_version $_def_directx +$_def_direct3d $_def_dvb $_def_dvb_head $_def_dvbin Index: DOCS/tech/MAINTAINERS =================================================================== --- DOCS/tech/MAINTAINERS (revision 27905) +++ DOCS/tech/MAINTAINERS (working copy) @@ -164,6 +164,7 @@ * vo_dfbmga.c - Ville Syrjälä * vo_directfb[2].c - Jiri Svoboda * vo_directx.c - Sascha Sommer + * vo_direct3d.c - Georgi Petrov * vo_dxr2.c - Alban Bedel * vo_dxr3.c - None * vo_fbdev.c - Joey Parrish