X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fdirectx%2Fvout_directx.c;h=c7ea2596306c0cd254ffd753b18d91d3f374711e;hb=cf5b3832dc6ad3fb4e55e9506e7e803d3e26ed53;hp=71297e9ae75d277ba2f89182ea74c740591cf005;hpb=248eb0b5b90523c8929c33dae781ca5b500c906d;p=vlc diff --git a/plugins/directx/vout_directx.c b/plugins/directx/vout_directx.c index 71297e9ae7..c7ea259630 100644 --- a/plugins/directx/vout_directx.c +++ b/plugins/directx/vout_directx.c @@ -2,7 +2,7 @@ * vout_directx.c: Windows DirectX video output display method ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: vout_directx.c,v 1.14 2001/11/28 15:08:05 massiot Exp $ + * $Id: vout_directx.c,v 1.30 2002/04/05 01:05:22 gbazin Exp $ * * Authors: Gildas Bazin * @@ -21,16 +21,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ -#define MODULE_NAME directx -#include "modules_inner.h" - -/* ToDo: - * - * Double buffering - * - * Port this plugin to Video Output IV - */ - /***************************************************************************** * Preamble: * @@ -38,72 +28,69 @@ * the best video quality (hardware interpolation when rescaling the picture) * and the fastest display as it requires less processing. * - * If YUV overlay is not supported the plugin will use an RGB offscreen video - * surface that will be blitted onto the primary surface (display) to - * effectively display the picture. this fallback method enables us to display + * If YUV overlay is not supported this plugin will use RGB offscreen video + * surfaces that will be blitted onto the primary surface (display) to + * effectively display the pictures. this fallback method enables us to display * video in window mode. - * Another fallback method (which isn't implemented yet) would be to use the - * primary surface as the video buffer. This would allow for better - * performance but this is restricted to fullscreen video. In short, - * implementing this is not considered high priority. + * Another fallback method (which isn't implemented) would be take the + * exclusive control of the screen so we could spare the blitting process and + * decode directly to video memory. This should theoretically allow for better + * performance (although on my system it is actually slower) but this is + * restricted to fullscreen video. * *****************************************************************************/ -#include "defs.h" - #include /* ENOMEM */ #include /* free() */ #include /* strerror() */ -#include -#include +#include -#if defined( _MSC_VER ) -# include -#else -# include -#endif +#include -#include "config.h" -#include "common.h" -#include "intf_msg.h" -#include "threads.h" -#include "mtime.h" -#include "tests.h" #include "netutils.h" #include "video.h" #include "video_output.h" #include "interface.h" -#include "main.h" - -#include "modules.h" -#include "modules_export.h" #include "vout_directx.h" +/***************************************************************************** + * DirectDraw GUIDs. + * Defining them here allows us to get rid of the dxguid library during + * the linking stage. + *****************************************************************************/ +#include +DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +DEFINE_GUID( IID_IDirectDrawSurface3, 0xDA044E00,0x69B2,0x11D0,0xA1,0xD5,0x00,0xAA,0x00,0xB8,0xDF,0xBB ); + /***************************************************************************** * Local prototypes. *****************************************************************************/ -static int vout_Probe ( probedata_t *p_data ); -static int vout_Create ( struct vout_thread_s * ); -static int vout_Init ( struct vout_thread_s * ); -static void vout_End ( struct vout_thread_s * ); -static void vout_Destroy ( struct vout_thread_s * ); -static int vout_Manage ( struct vout_thread_s * ); -static void vout_Display ( struct vout_thread_s * ); -static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green, - u16 *blue, u16 *transp ); +static int vout_Create ( vout_thread_t * ); +static void vout_Destroy ( vout_thread_t * ); +static int vout_Init ( vout_thread_t * ); +static void vout_End ( vout_thread_t * ); +static int vout_Manage ( vout_thread_t * ); +static void vout_Render ( vout_thread_t *, picture_t * ); +static void vout_Display ( vout_thread_t *, picture_t * ); + +static int NewPictureVec ( vout_thread_t *, picture_t *, int ); +static void FreePictureVec ( vout_thread_t *, picture_t *, int ); +static int UpdatePictureStruct( vout_thread_t *, picture_t *, int ); static int DirectXInitDDraw ( vout_thread_t *p_vout ); -static int DirectXCreateDisplay ( vout_thread_t *p_vout ); -static int DirectXCreateSurface ( vout_thread_t *p_vout ); -static int DirectXCreateClipper ( vout_thread_t *p_vout ); -static int DirectXUpdateOverlay ( vout_thread_t *p_vout ); static void DirectXCloseDDraw ( vout_thread_t *p_vout ); +static int DirectXCreateDisplay ( vout_thread_t *p_vout ); static void DirectXCloseDisplay ( vout_thread_t *p_vout ); -static void DirectXCloseSurface ( vout_thread_t *p_vout ); -static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *coordinates ); +static int DirectXCreateSurface ( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE3 *, int, int ); +static void DirectXCloseSurface ( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE3 ); +static int DirectXCreateClipper ( vout_thread_t *p_vout ); +static void DirectXGetDDrawCaps ( vout_thread_t *p_vout ); +static int DirectXGetSurfaceDesc ( picture_t *p_pic ); /***************************************************************************** * Functions exported as capabilities. They are declared as static so that @@ -111,34 +98,13 @@ static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *coordinates ); *****************************************************************************/ void _M( vout_getfunctions )( function_list_t * p_function_list ) { - p_function_list->pf_probe = vout_Probe; p_function_list->functions.vout.pf_create = vout_Create; p_function_list->functions.vout.pf_init = vout_Init; p_function_list->functions.vout.pf_end = vout_End; p_function_list->functions.vout.pf_destroy = vout_Destroy; p_function_list->functions.vout.pf_manage = vout_Manage; + p_function_list->functions.vout.pf_render = vout_Render; p_function_list->functions.vout.pf_display = vout_Display; - p_function_list->functions.vout.pf_setpalette = vout_SetPalette; -} - -/***************************************************************************** - * vout_Probe: probe the video driver and return a score - ***************************************************************************** - * This function tries to initialize Windows DirectX and returns a score to - * the plugin manager so that it can select the best plugin. - *****************************************************************************/ -static int vout_Probe( probedata_t *p_data ) -{ - - if( TestMethod( VOUT_METHOD_VAR, "directx" ) ) - { - return( 999 ); - } - - /* Check that at least DirectX5 is installed on the computer */ - /* Fixme */ - - return( 400 ); } /***************************************************************************** @@ -159,37 +125,25 @@ static int vout_Create( vout_thread_t *p_vout ) /* Initialisations */ p_vout->p_sys->p_ddobject = NULL; p_vout->p_sys->p_display = NULL; - p_vout->p_sys->p_surface = NULL; + p_vout->p_sys->p_current_surface = NULL; p_vout->p_sys->p_clipper = NULL; p_vout->p_sys->hbrush = NULL; p_vout->p_sys->hwnd = NULL; p_vout->p_sys->i_changes = 0; p_vout->p_sys->b_event_thread_die = 0; - p_vout->p_sys->b_display_enabled = 0; + p_vout->p_sys->b_caps_overlay_clipping = 0; + SetRectEmpty( &p_vout->p_sys->rect_display ); + p_vout->p_sys->b_using_overlay = !config_GetIntVariable( "nooverlay" ); - p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */ + p_vout->p_sys->b_cursor = 1; p_vout->p_sys->b_cursor_autohidden = 0; p_vout->p_sys->i_lastmoved = mdate(); - p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR, - VOUT_FULLSCREEN_DEFAULT ); -#if 0 - p_vout->b_need_render = !main_GetIntVariable( VOUT_OVERLAY_VAR, - VOUT_OVERLAY_DEFAULT ); -#else - p_vout->b_need_render = 0; /* default = overlay */ -#endif - p_vout->p_sys->i_window_width = main_GetIntVariable( VOUT_WIDTH_VAR, - VOUT_WIDTH_DEFAULT ); - p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR, - VOUT_HEIGHT_DEFAULT ); - /* We don't know yet the dimensions of the video so the best guess is to - * pick the same as the window */ - p_vout->p_sys->i_image_width = p_vout->p_sys->i_window_width; - p_vout->p_sys->i_image_height = p_vout->p_sys->i_window_height; - - + /* Set main window's size */ + p_vout->p_sys->i_window_width = p_vout->i_window_width; + p_vout->p_sys->i_window_height = p_vout->i_window_height; + /* Set locks and condition variables */ vlc_mutex_init( &p_vout->p_sys->event_thread_lock ); vlc_cond_init( &p_vout->p_sys->event_thread_wait ); @@ -214,13 +168,13 @@ static int vout_Create( vout_thread_t *p_vout ) } /* We need to wait for the actual creation of the thread and window */ + vlc_mutex_lock( &p_vout->p_sys->event_thread_lock ); if( p_vout->p_sys->i_event_thread_status == THREAD_CREATE ) { - vlc_mutex_lock( &p_vout->p_sys->event_thread_lock ); vlc_cond_wait ( &p_vout->p_sys->event_thread_wait, &p_vout->p_sys->event_thread_lock ); - vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock ); } + vlc_mutex_unlock( &p_vout->p_sys->event_thread_lock ); if( p_vout->p_sys->i_event_thread_status != THREAD_READY ) { intf_ErrMsg( "vout error: DirectXEventThread failed" ); @@ -228,8 +182,8 @@ static int vout_Create( vout_thread_t *p_vout ) return( 1 ); } + intf_WarnMsg( 3, "vout: vout_Create DirectXEventThread running" ); - intf_WarnMsg( 3, "vout : vout_Create DirectXEventThread running" ); /* Initialise DirectDraw */ if( DirectXInitDDraw( p_vout ) ) @@ -262,16 +216,41 @@ static int vout_Create( vout_thread_t *p_vout ) return ( 1 ); } + /* Attach the current thread input queue to the events thread qeue. + * This allows us to hide or show the cursor in vout_Manage() */ + ShowCursor( TRUE ); ShowCursor( FALSE ); /* create input queue */ + AttachThreadInput( GetCurrentThreadId(), + GetWindowThreadProcessId( p_vout->p_sys->hwnd, NULL ), + 1 ); + return( 0 ); } /***************************************************************************** * vout_Init: initialize DirectX video thread output method ***************************************************************************** - * + * This function create the directx surfaces needed by the output thread. + * It is called at the beginning of the thread. *****************************************************************************/ static int vout_Init( vout_thread_t *p_vout ) { + + /* Initialize the output structure. + * Since DirectDraw can do rescaling for us, stick to the default + * coordinates and aspect. */ + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + +#define MAX_DIRECTBUFFERS 1 + + NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS ); + + /* Change the window title bar text */ + if( p_vout->p_sys->b_using_overlay ) + SetWindowText( p_vout->p_sys->hwnd, + "VLC DirectX (using hardware overlay)" ); + return( 0 ); } @@ -283,6 +262,7 @@ static int vout_Init( vout_thread_t *p_vout ) *****************************************************************************/ static void vout_End( vout_thread_t *p_vout ) { + FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES ); return; } @@ -301,9 +281,10 @@ static void vout_Destroy( vout_thread_t *p_vout ) p_vout->p_sys->b_event_thread_die = 1; /* we need to be sure DirectXEventThread won't stay stuck in GetMessage, * so we send a fake message */ - if( p_vout->p_sys->i_event_thread_status == THREAD_READY ) + if( p_vout->p_sys->i_event_thread_status == THREAD_READY && + p_vout->p_sys->hwnd ) { - PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'q', 0); + PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'^', 0); vlc_thread_join( p_vout->p_sys->event_thread_id ); } @@ -317,13 +298,12 @@ static void vout_Destroy( vout_thread_t *p_vout ) /***************************************************************************** * vout_Manage: handle Sys events ***************************************************************************** - * This function should be called regularly by video output thread. It returns - * a non null value if an error occured. + * This function should be called regularly by the video output thread. + * It returns a non null value if an error occured. *****************************************************************************/ static int vout_Manage( vout_thread_t *p_vout ) { WINDOWPLACEMENT window_placement; - extern int b_directx_update_overlay; /* We used to call the Win32 PeekMessage function here to read the window * messages. But since window can stay blocked into this function for a @@ -337,11 +317,10 @@ static int vout_Manage( vout_thread_t *p_vout ) || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE) { intf_WarnMsg( 3, "vout: vout_Manage Scale Change" ); - if( p_vout->b_need_render ) - InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE ); - if( DirectXUpdateOverlay( p_vout ) ) - /* failed so try again next time */ - PostMessage( p_vout->p_sys->hwnd, WM_CHAR, (WPARAM)'S', 0); + if( !p_vout->p_sys->b_using_overlay ) + InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE ); + else + DirectXUpdateOverlay( p_vout ); p_vout->i_changes &= ~VOUT_SCALE_CHANGE; p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE; } @@ -350,45 +329,15 @@ static int vout_Manage( vout_thread_t *p_vout ) * Size Change */ if( p_vout->i_changes & VOUT_SIZE_CHANGE - || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE - || b_directx_update_overlay ) + || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE ) { intf_WarnMsg( 3, "vout: vout_Manage Size Change" ); - if( DirectXUpdateOverlay( p_vout ) ) - /* failed so try again next time */ - PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0); + if( !p_vout->p_sys->b_using_overlay ) + InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE ); + else + DirectXUpdateOverlay( p_vout ); p_vout->i_changes &= ~VOUT_SIZE_CHANGE; p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE; - b_directx_update_overlay = 0; - } - - /* - * YUV Change - */ - if( p_vout->i_changes & VOUT_YUV_CHANGE - || p_vout->p_sys->i_changes & VOUT_YUV_CHANGE ) - { - p_vout->b_need_render = ! p_vout->b_need_render; - - /* Need to reopen display */ - DirectXCloseSurface( p_vout ); - if( DirectXCreateSurface( p_vout ) ) - { - intf_ErrMsg( "error: can't reopen display after YUV change" ); - return( 1 ); - } - - /* Repaint the window background (needed by the overlay surface) */ - if( !p_vout->b_need_render ) - { - InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE ); - p_vout->p_sys->b_display_enabled = 1; - if( DirectXUpdateOverlay( p_vout ) ) - /* failed so try again next time */ - PostMessage( p_vout->p_sys->hwnd, WM_APP, 0, 0); - } - p_vout->i_changes &= ~VOUT_YUV_CHANGE; - p_vout->p_sys->i_changes &= ~VOUT_YUV_CHANGE; } /* @@ -436,6 +385,7 @@ static int vout_Manage( vout_thread_t *p_vout ) ShowCursor( FALSE ); } +#if 0 if( p_vout->i_changes & VOUT_CURSOR_CHANGE || p_vout->p_sys->i_changes & VOUT_CURSOR_CHANGE ) { @@ -447,38 +397,32 @@ static int vout_Manage( vout_thread_t *p_vout ) p_vout->i_changes &= ~VOUT_CURSOR_CHANGE; p_vout->p_sys->i_changes &= ~VOUT_CURSOR_CHANGE; } +#endif + + /* Check if the event thread is still running */ + if( p_vout->p_sys->b_event_thread_die ) + return 1; /* exit */ return( 0 ); } /***************************************************************************** - * vout_SetPalette: sets an 8 bpp palette - ***************************************************************************** - * This function sets the palette given as an argument. It does not return - * anything, but could later send information on which colors it was unable - * to set. + * vout_Render: render previously calculated output *****************************************************************************/ -static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green, - u16 *blue, u16 *transp) +static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic ) { - /* Nothing yet */ - return; + ; } /***************************************************************************** * vout_Display: displays previously rendered output ***************************************************************************** - * This function send the currently rendered image to the display, wait until - * it is displayed and switch the two rendering buffer, preparing next frame. + * This function sends the currently rendered image to the display, wait until + * it is displayed and switch the two rendering buffers, preparing next frame. *****************************************************************************/ -static void vout_Display( vout_thread_t *p_vout ) +static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic ) { - DDSURFACEDESC ddsd; - HRESULT dxresult; - - int i; - int i_image_width; - int i_image_height; + HRESULT dxresult; if( (p_vout->p_sys->p_display == NULL) ) { @@ -486,79 +430,35 @@ static void vout_Display( vout_thread_t *p_vout ) return; } - /* if the size of the decoded pictures has changed then we close the - * video surface (which doesn't have the right size anymore). */ - i_image_width = ( p_vout->p_rendered_pic ) ? - p_vout->p_rendered_pic->i_width : p_vout->p_sys->i_image_width; - i_image_height = ( p_vout->p_rendered_pic ) ? - p_vout->p_rendered_pic->i_height : p_vout->p_sys->i_image_height; - - if( p_vout->p_sys->i_image_width != i_image_width - || p_vout->p_sys->i_image_height != i_image_height ) - { - intf_WarnMsg( 3, "vout: video surface size changed" ); - p_vout->p_sys->i_image_width = i_image_width; - p_vout->p_sys->i_image_height = i_image_height; - DirectXCloseSurface( p_vout ); - } - - if( p_vout->b_need_render ) + if( !p_vout->p_sys->b_using_overlay ) { - RECT rect_window; - POINT point_window; DDBLTFX ddbltfx; - - /* Nothing yet */ - if( p_vout->p_sys->p_surface == NULL ) - { - intf_WarnMsg( 3, "vout: no video surface, open one..." ); - if( DirectXCreateSurface( p_vout ) ) - { - intf_WarnMsg( 3, "vout: cannot open a new video surface !!" ); - return; - } - /* Display the surface */ - p_vout->p_sys->b_display_enabled = 1; - } - - /* Now get the coordinates of the window. We don't actually want the - * window coordinates but these of the usable surface inside the window - * By specification GetClientRect will always set rect_window.left and - * rect_window.top to 0 because the Client area is always relative to - * the container window */ - GetClientRect(p_vout->p_sys->hwnd, &rect_window); - - point_window.x = 0; - point_window.y = 0; - ClientToScreen(p_vout->p_sys->hwnd, &point_window); - rect_window.left = point_window.x; - rect_window.top = point_window.y; - - point_window.x = rect_window.right; - point_window.y = rect_window.bottom; - ClientToScreen(p_vout->p_sys->hwnd, &point_window); - rect_window.right = point_window.x; - rect_window.bottom = point_window.y; - - /* We want to keep the aspect ratio of the video */ -#if 0 - if( p_vout->b_scale ) - { - DirectXKeepAspectRatio( p_vout, &rect_window ); - } -#endif /* We ask for the "NOTEARING" option */ memset( &ddbltfx, 0, sizeof(DDBLTFX) ); ddbltfx.dwSize = sizeof(DDBLTFX); - ddbltfx.dwDDFX = DDBLTFX_NOTEARING; + ddbltfx.dwDDFX = DDBLTFX_NOTEARING | DDBLT_ASYNC; /* Blit video surface to display */ dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display, - &rect_window, - p_vout->p_sys->p_surface, - NULL, + &p_vout->p_sys->rect_dest_clipped, + p_pic->p_sys->p_surface, + &p_vout->p_sys->rect_src_clipped, 0, &ddbltfx ); + if ( dxresult == DDERR_SURFACELOST ) + { + /* Our surface can be lost so be sure + * to check this and restore it if needed */ + IDirectDrawSurface3_Restore( p_vout->p_sys->p_display ); + + /* Now that the surface has been restored try to display again */ + dxresult = IDirectDrawSurface3_Blt(p_vout->p_sys->p_display, + &p_vout->p_sys->rect_dest_clipped, + p_pic->p_sys->p_surface, + &p_vout->p_sys->rect_src_clipped, + 0, &ddbltfx ); + } + if( dxresult != DD_OK ) { intf_WarnMsg( 3, "vout: could not Blit the surface" ); @@ -566,107 +466,48 @@ static void vout_Display( vout_thread_t *p_vout ) } } - else + else /* using overlay */ { - /* - * p_vout->p_rendered_pic->p_y/u/v contains the YUV buffers to - * render - */ - /* TODO: support for streams other than 4:2:0 */ - - if( p_vout->p_sys->p_surface == NULL ) - { - intf_WarnMsg( 3, "vout: no video surface, open one..." ); - if( DirectXCreateSurface( p_vout ) ) - { - intf_WarnMsg( 3, "vout: cannot open a new video surface !!" ); - return; - } - } - /* Lock the overlay surface */ - memset( &ddsd, 0, sizeof( DDSURFACEDESC )); - ddsd.dwSize = sizeof(DDSURFACEDESC); - dxresult = IDirectDrawSurface3_Lock(p_vout->p_sys->p_surface, NULL, - &ddsd, DDLOCK_NOSYSLOCK, NULL); +#if 0 + /* Flip the overlay buffers */ + dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface, + NULL, DDFLIP_WAIT ); if ( dxresult == DDERR_SURFACELOST ) { - /* Your surface can be lost (thanks to windows) so be sure + /* Our surface can be lost so be sure * to check this and restore it if needed */ - dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface ); - dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, - NULL, &ddsd, DDLOCK_NOSYSLOCK - | DDLOCK_WAIT, NULL); + IDirectDrawSurface3_Restore( p_vout->p_sys->p_display ); + IDirectDrawSurface3_Restore( p_pic->p_sys->p_front_surface ); + + /* Now that the surface has been restored try to display again */ + dxresult = IDirectDrawSurface3_Flip( p_pic->p_sys->p_front_surface, + NULL, DDFLIP_WAIT ); + DirectXUpdateOverlay( p_vout ); } + if( dxresult != DD_OK ) - { - intf_WarnMsg( 3, "vout: could not lock the surface" ); - return; - } + intf_WarnMsg( 8, "vout: couldn't flip overlay surface" ); +#endif - /* Now we can do the actual image copy. - * The copy has to be done line by line because of the special case - * when the Pitch does not equal the width of the picture */ - for( i=0; i < ddsd.dwHeight/2; i++) + if( !DirectXGetSurfaceDesc( p_pic ) ) { -#ifdef NONAMELESSUNION - /* copy Y, we copy two lines at once */ - memcpy(ddsd.lpSurface + i*2*ddsd.u1.lPitch, - p_vout->p_rendered_pic->p_y + i*2*i_image_width, - i_image_width); - memcpy(ddsd.lpSurface + (i*2+1)*ddsd.u1.lPitch, - p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width, - i_image_width); - /* then V */ - memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch) - + i * ddsd.u1.lPitch/2, - p_vout->p_rendered_pic->p_v + i*i_image_width/2, - i_image_width/2); - /* and U */ - memcpy((ddsd.lpSurface + ddsd.dwHeight * ddsd.u1.lPitch) - + (ddsd.dwHeight * ddsd.u1.lPitch/4) - + i * ddsd.u1.lPitch/2, - p_vout->p_rendered_pic->p_u + i*i_image_width/2, - i_image_width/2); -#else - /* copy Y, we copy two lines at once */ - memcpy((u8*)ddsd.lpSurface + i*2*ddsd.lPitch, - p_vout->p_rendered_pic->p_y + i*2*i_image_width, - i_image_width); - memcpy((u8*)ddsd.lpSurface + (i*2+1)*ddsd.lPitch, - p_vout->p_rendered_pic->p_y + (i*2+1)*i_image_width, - i_image_width); - /* then V */ - memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch) - + i * ddsd.lPitch/2, - p_vout->p_rendered_pic->p_v + i*i_image_width/2, - i_image_width/2); - /* and U */ - memcpy(((u8*)ddsd.lpSurface + ddsd.dwHeight * ddsd.lPitch) - + (ddsd.dwHeight * ddsd.lPitch/4) - + i * ddsd.lPitch/2, - p_vout->p_rendered_pic->p_u + i*i_image_width/2, - i_image_width/2); -#endif /* NONAMELESSUNION */ - + /* AAARRGG */ + intf_ErrMsg( "vout error: vout_Display cannot get surface desc" ); + return; } - /* Unlock the Surface */ - dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface, - ddsd.lpSurface ); - - /* If display not enabled yet then enable */ - if( !p_vout->p_sys->b_display_enabled ) + if( !UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) ) { - p_vout->p_sys->b_display_enabled = 1; - DirectXUpdateOverlay( p_vout ); + /* AAARRGG */ + intf_ErrMsg( "vout error: vout_Display unvalid pic chroma" ); + return; } + /* set currently displayed pic */ + p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface; } - /* The first time this function is called it enables the display */ - p_vout->p_sys->b_display_enabled = 1; - } @@ -746,6 +587,9 @@ static int DirectXInitDDraw( vout_thread_t *p_vout ) IDirectDraw_Release( p_ddobject ); } + /* Probe the capabilities of the hardware */ + DirectXGetDDrawCaps( p_vout ); + intf_WarnMsg( 3, "vout: End DirectXInitDDraw" ); return( 0 ); } @@ -761,11 +605,11 @@ static int DirectXCreateDisplay( vout_thread_t *p_vout ) HRESULT dxresult; DDSURFACEDESC ddsd; LPDIRECTDRAWSURFACE p_display; - DDPIXELFORMAT ddpfPixelFormat; + DDPIXELFORMAT pixel_format; intf_WarnMsg( 3, "vout: DirectXCreateDisplay" ); - /* Now create the primary surface. This surface is what you actually see + /* Now get the primary surface. This surface is what you actually see * on your screen */ memset( &ddsd, 0, sizeof( DDSURFACEDESC )); ddsd.dwSize = sizeof(DDSURFACEDESC); @@ -777,7 +621,7 @@ static int DirectXCreateDisplay( vout_thread_t *p_vout ) &p_display, NULL ); if( dxresult != DD_OK ) { - intf_ErrMsg( "vout error: can't create direct draw primary surface." ); + intf_ErrMsg( "vout error: can't get direct draw primary surface." ); p_vout->p_sys->p_display = NULL; return( 1 ); } @@ -799,39 +643,75 @@ static int DirectXCreateDisplay( vout_thread_t *p_vout ) } - /* We need to fill in some information for the video output thread. - * We do this here because it must be done before the video_output - * thread enters its main loop - and DirectXCreateSurface can be called - * after that ! */ - ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display, - &ddpfPixelFormat ); -#ifdef NONAMELESSUNION - p_vout->i_screen_depth = ddpfPixelFormat.u1.dwRGBBitCount; - p_vout->i_bytes_per_pixel = ddpfPixelFormat.u1.dwRGBBitCount/8; - - p_vout->i_red_mask = ddpfPixelFormat.u2.dwRBitMask; - p_vout->i_green_mask = ddpfPixelFormat.u3.dwGBitMask; - p_vout->i_blue_mask = ddpfPixelFormat.u4.dwBBitMask; -#else - p_vout->i_screen_depth = ddpfPixelFormat.dwRGBBitCount; - p_vout->i_bytes_per_pixel = ddpfPixelFormat.dwRGBBitCount/8; - - p_vout->i_red_mask = ddpfPixelFormat.dwRBitMask; - p_vout->i_green_mask = ddpfPixelFormat.dwGBitMask; - p_vout->i_blue_mask = ddpfPixelFormat.dwBBitMask; -#endif /* NONAMELESSUNION */ - - /* Create a video surface. This function will try to create an - * YUV overlay first and if it can't it will create a simple RGB surface */ - if( DirectXCreateSurface( p_vout ) ) + /* The clipper will be used only in non-overlay mode */ + DirectXCreateClipper( p_vout ); + + +#if 1 + /* compute the colorkey pixel value from the RGB value we've got */ + memset( &pixel_format, 0, sizeof( DDPIXELFORMAT )); + pixel_format.dwSize = sizeof( DDPIXELFORMAT ); + dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display, + &pixel_format ); + if( dxresult != DD_OK ) + intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" ); + p_vout->p_sys->i_colorkey = (DWORD)((( p_vout->p_sys->i_rgb_colorkey + * pixel_format.dwRBitMask) / 255) + & pixel_format.dwRBitMask); +#endif + + return( 0 ); +} + + +/***************************************************************************** + * DirectXCreateClipper: Create a clipper that will be used when blitting the + * RGB surface to the main display. + ***************************************************************************** + * This clipper prevents us to modify by mistake anything on the screen + * which doesn't belong to our window. For example when a part of our video + * window is hidden by another window. + *****************************************************************************/ +static int DirectXCreateClipper( vout_thread_t *p_vout ) +{ + HRESULT dxresult; + + intf_WarnMsg( 3, "vout: DirectXCreateClipper" ); + + /* Create the clipper */ + dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0, + &p_vout->p_sys->p_clipper, NULL ); + if( dxresult != DD_OK ) { - intf_ErrMsg( "vout error: can't create a video surface." ); - IDirectDrawSurface3_Release( p_vout->p_sys->p_display ); - p_vout->p_sys->p_display = NULL; + intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." ); + p_vout->p_sys->p_clipper = NULL; return( 1 ); } - + + /* associate the clipper to the window */ + dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0, + p_vout->p_sys->hwnd); + if( dxresult != DD_OK ) + { + intf_WarnMsg( 3, + "vout: DirectXCreateClipper can't attach clipper to window." ); + IDirectDrawSurface_Release( p_vout->p_sys->p_clipper ); + p_vout->p_sys->p_clipper = NULL; + return( 1 ); + } + + /* associate the clipper with the surface */ + dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display, + p_vout->p_sys->p_clipper); + if( dxresult != DD_OK ) + { + intf_WarnMsg( 3, + "vout: DirectXCreateClipper can't attach clipper to surface." ); + IDirectDrawSurface_Release( p_vout->p_sys->p_clipper ); + p_vout->p_sys->p_clipper = NULL; + return( 1 ); + } + return( 0 ); } @@ -839,61 +719,24 @@ static int DirectXCreateDisplay( vout_thread_t *p_vout ) * DirectXCreateSurface: create an YUV overlay or RGB surface for the video. ***************************************************************************** * The best method of display is with an YUV overlay because the YUV->RGB - * conversion is done in hardware, so we'll try to create this surface first. - * If we fail, we'll try to create a plain RGB surface. + * conversion is done in hardware. + * You can also create a plain RGB surface. * ( Maybe we could also try an RGB overlay surface, which could have hardware * scaling and which would also be faster in window mode because you don't * need to do any blitting to the main display...) *****************************************************************************/ -static int DirectXCreateSurface( vout_thread_t *p_vout ) +static int DirectXCreateSurface( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE3 *pp_surface_final, + int i_chroma, int b_overlay ) { HRESULT dxresult; - DDSURFACEDESC ddsd; LPDIRECTDRAWSURFACE p_surface; - DDCAPS ddcaps; + DDSURFACEDESC ddsd; intf_WarnMsg( 3, "vout: DirectXCreateSurface" ); - /* Disable display */ - p_vout->p_sys->b_display_enabled = 0; - -#if 1 - /* Probe the capabilities of the hardware */ - /* This is just an indication of whether or not we'll support overlay, - * but with this test we don't know if we support YUV overlay */ - memset( &ddcaps, 0, sizeof( DDCAPS )); - ddcaps.dwSize = sizeof(DDCAPS); - dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject, - &ddcaps, NULL ); - if(dxresult != DD_OK ) - { - intf_WarnMsg( 3,"vout error: can't get caps." ); - } - else - { - BOOL bHasOverlay, bHasColorKey, bCanStretch; - - /* Determine if the hardware supports overlay surfaces */ - bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) == - DDCAPS_OVERLAY) ? TRUE : FALSE; - /* Determine if the hardware supports colorkeying */ - bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) == - DDCAPS_COLORKEY) ? TRUE : FALSE; - /* Determine if the hardware supports scaling of the overlay surface */ - bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) == - DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE; - intf_WarnMsg( 3, "vout: Dx Caps: overlay=%i colorkey=%i stretch=%i", - bHasOverlay, bHasColorKey, bCanStretch ); - -#if 0 - if( !bHasOverlay ) p_vout->b_need_render = 1; -#endif - } -#endif - - /* Create the video surface */ - if( !p_vout->b_need_render ) + if( b_overlay ) { /* Now try to create the YUV overlay surface. * This overlay will be displayed on top of the primary surface. @@ -907,23 +750,23 @@ static int DirectXCreateSurface( vout_thread_t *p_vout ) ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC; - ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2'); -#ifdef NONAMELESSUNION - ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16; -#else - ddsd.ddpfPixelFormat.dwYUVBitCount = 16; -#endif + ddsd.ddpfPixelFormat.dwFourCC = i_chroma; ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | + //DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT; - ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY; - ddsd.dwHeight = p_vout->p_sys->i_image_height; - ddsd.dwWidth = p_vout->p_sys->i_image_width; + ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | + //DDSCAPS_COMPLEX | + //DDSCAPS_FLIP | + DDSCAPS_VIDEOMEMORY; + ddsd.dwHeight = p_vout->render.i_height; + ddsd.dwWidth = p_vout->render.i_width; ddsd.dwBackBufferCount = 1; /* One back buffer */ dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject, - &ddsd, &p_surface, NULL ); + &ddsd, + &p_surface, NULL ); if( dxresult == DD_OK ) { intf_WarnMsg( 3,"vout: DirectX YUV overlay created successfully" ); @@ -931,24 +774,27 @@ static int DirectXCreateSurface( vout_thread_t *p_vout ) else { intf_ErrMsg( "vout error: can't create YUV overlay surface." ); - p_vout->b_need_render = 1; + *pp_surface_final = NULL; + return 0; } } - if( p_vout->b_need_render ) + if( !b_overlay ) { /* Now try to create a plain RGB surface. */ - memset( &ddsd, 0, sizeof( DDSURFACEDESC )); + memset( &ddsd, 0, sizeof( DDSURFACEDESC ) ); ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - ddsd.dwHeight = p_vout->p_sys->i_image_height; - ddsd.dwWidth = p_vout->p_sys->i_image_width; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | + DDSCAPS_SYSTEMMEMORY; + ddsd.dwHeight = p_vout->render.i_height; + ddsd.dwWidth = p_vout->render.i_width; dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject, - &ddsd, &p_surface, NULL ); + &ddsd, + &p_surface, NULL ); if( dxresult == DD_OK ) { intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" ); @@ -956,167 +802,24 @@ static int DirectXCreateSurface( vout_thread_t *p_vout ) else { intf_ErrMsg( "vout error: can't create RGB surface." ); - p_vout->p_sys->p_surface = NULL; - return( 1 ); + *pp_surface_final = NULL; + return 0; } } /* Now that the surface is created, try to get a newer DirectX interface */ dxresult = IDirectDrawSurface_QueryInterface( p_surface, - &IID_IDirectDrawSurface3, - (LPVOID *)&p_vout->p_sys->p_surface ); + &IID_IDirectDrawSurface3, + (LPVOID *)pp_surface_final ); + IDirectDrawSurface_Release( p_surface ); /* Release the old interface */ if ( dxresult != DD_OK ) { intf_ErrMsg( "vout error: can't get IDirectDrawSurface3 interface." ); - IDirectDrawSurface_Release( p_surface ); - p_vout->p_sys->p_surface = NULL; - return( 1 ); - } - else - { - /* Release the old interface */ - IDirectDrawSurface_Release( p_surface ); - } - - if( !p_vout->b_need_render ) - { - /* Hide the overlay for now */ - IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface, - NULL, - p_vout->p_sys->p_display, - NULL, - DDOVER_HIDE, - NULL); - } - else - { - DirectXCreateClipper( p_vout ); + *pp_surface_final = NULL; + return 0; } - - /* From now on, do some initialisation for video_output */ - - /* if we want a valid pointer to the surface memory, we must lock - * the surface */ - - memset( &ddsd, 0, sizeof( DDSURFACEDESC )); - ddsd.dwSize = sizeof(DDSURFACEDESC); - dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, NULL, &ddsd, - DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL); - if ( dxresult == DDERR_SURFACELOST ) - { - /* Your surface can be lost so be sure - * to check this and restore it if needed */ - dxresult = IDirectDrawSurface3_Restore( p_vout->p_sys->p_surface ); - dxresult = IDirectDrawSurface3_Lock( p_vout->p_sys->p_surface, - NULL, &ddsd, DDLOCK_NOSYSLOCK - | DDLOCK_WAIT, NULL); - } - if( dxresult != DD_OK ) - { - intf_ErrMsg( "vout: DirectXCreateDisplay could not lock the surface" ); - return( 1 ); - } - - /* Set the pointer to the surface memory */ - p_vout->p_sys->p_directx_buf[ 0 ] = ddsd.lpSurface; - /* back buffer, none for now */ - p_vout->p_sys->p_directx_buf[ 1 ] = ddsd.lpSurface; - - /* Set thread information */ - p_vout->i_width = ddsd.dwWidth; - p_vout->i_height = ddsd.dwHeight; -#ifdef NONAMELESSUNION - p_vout->i_bytes_per_line = ddsd.u1.lPitch; -#else - p_vout->i_bytes_per_line = ddsd.lPitch; -#endif /* NONAMELESSUNION */ - - - if( p_vout->b_need_render ) - { - /* For an RGB surface we need to fill in some more info */ -#ifdef NONAMELESSUNION - p_vout->i_screen_depth = ddsd.ddpfPixelFormat.u1.dwRGBBitCount; - p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.u1.dwRGBBitCount/8; - - p_vout->i_red_mask = ddsd.ddpfPixelFormat.u2.dwRBitMask; - p_vout->i_green_mask = ddsd.ddpfPixelFormat.u3.dwGBitMask; - p_vout->i_blue_mask = ddsd.ddpfPixelFormat.u4.dwBBitMask; -#else - p_vout->i_screen_depth = ddsd.ddpfPixelFormat.dwRGBBitCount; - p_vout->i_bytes_per_pixel = ddsd.ddpfPixelFormat.dwRGBBitCount/8; - - p_vout->i_red_mask = ddsd.ddpfPixelFormat.dwRBitMask; - p_vout->i_green_mask = ddsd.ddpfPixelFormat.dwGBitMask; - p_vout->i_blue_mask = ddsd.ddpfPixelFormat.dwBBitMask; - -#endif /* NONAMELESSUNION */ - } - - /* Unlock the Surface */ - dxresult = IDirectDrawSurface3_Unlock(p_vout->p_sys->p_surface, - ddsd.lpSurface ); - - /* Set and initialize buffers */ - p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_directx_buf[ 0 ], - p_vout->p_sys->p_directx_buf[ 1 ] ); - - - return ( 0 ); -} - - -/***************************************************************************** - * DirectXCreateClipper: Create a clipper that will be used when blitting the - * RGB surface to the main display. - ***************************************************************************** - * This clipper prevents us to modify by mistake anything on the screen - * which doesn't belong to our window. For example when a part of our video - * window is hidden by another window. - *****************************************************************************/ -static int DirectXCreateClipper( vout_thread_t *p_vout ) -{ - HRESULT dxresult; - - intf_WarnMsg( 3, "vout: DirectXCreateClipper" ); - - /* Create the clipper */ - dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0, - &p_vout->p_sys->p_clipper, NULL ); - if( dxresult != DD_OK ) - { - intf_WarnMsg( 3, "vout: DirectXCreateClipper can't create clipper." ); - IDirectDrawSurface_Release( p_vout->p_sys->p_clipper ); - p_vout->p_sys->p_clipper = NULL; - return( 1 ); - } - - /* associate the clipper to the window */ - dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0, - p_vout->p_sys->hwnd); - if( dxresult != DD_OK ) - { - intf_WarnMsg( 3, - "vout: DirectXCreateClipper can't attach clipper to window." ); - IDirectDrawSurface_Release( p_vout->p_sys->p_clipper ); - p_vout->p_sys->p_clipper = NULL; - return( 1 ); - } - - /* associate the clipper with the surface */ - dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display, - p_vout->p_sys->p_clipper); - if( dxresult != DD_OK ) - { - intf_WarnMsg( 3, - "vout: DirectXCreateClipper can't attach clipper to surface." ); - IDirectDrawSurface_Release( p_vout->p_sys->p_clipper ); - p_vout->p_sys->p_clipper = NULL; - return( 1 ); - } - - return( 0 ); + return 1; } @@ -1127,155 +830,45 @@ static int DirectXCreateClipper( vout_thread_t *p_vout ) * Ususally the overlay is moved by the user and thus, by a move or resize * event (in vout_Manage). *****************************************************************************/ -static int DirectXUpdateOverlay( vout_thread_t *p_vout ) +void DirectXUpdateOverlay( vout_thread_t *p_vout ) { DDOVERLAYFX ddofx; - RECT rect_window, rect_window_backup, rect_image; - POINT point_window; DWORD dwFlags; HRESULT dxresult; - DWORD dw_colorkey; - DDPIXELFORMAT pixel_format; - DDSURFACEDESC ddsd; - - if( p_vout->p_sys->p_surface == NULL || p_vout->b_need_render ) - { - intf_WarnMsg( 3, "vout: DirectXUpdateOverlay no overlay !!" ); - return( 0 ); - } - if( !p_vout->p_rendered_pic ) + if( p_vout->p_sys->p_current_surface == NULL || + !p_vout->p_sys->b_using_overlay ) { - intf_WarnMsg( 3, "vout: DirectXUpdateOverlay p_rendered_pic=NULL !" ); - return( 1 ); - } - - if( !p_vout->p_sys->b_display_enabled ) - { - return( 0 ); - } - - /* Now get the coordinates of the window. We don't actually want the - * window coordinates but these of the usable surface inside the window. - * By specification GetClientRect will always set rect_window.left and - * rect_window.top to 0 because the Client area is always relative to the - * container window */ - GetClientRect(p_vout->p_sys->hwnd, &rect_window); - - point_window.x = 0; - point_window.y = 0; - ClientToScreen(p_vout->p_sys->hwnd, &point_window); - rect_window.left = point_window.x; - rect_window.top = point_window.y; - - point_window.x = rect_window.right; - point_window.y = rect_window.bottom; - ClientToScreen(p_vout->p_sys->hwnd, &point_window); - rect_window.right = point_window.x; - rect_window.bottom = point_window.y; - - - /* We want to keep the aspect ratio of the video */ - if( p_vout->b_scale ) - { - DirectXKeepAspectRatio( p_vout, &rect_window ); + intf_WarnMsg( 5, "vout: DirectXUpdateOverlay no overlay !!" ); + return; } - /* It seems we can't feed the UpdateOverlay directdraw function with - * negative values so we have to clip the computed rectangles */ - memset( &ddsd, 0, sizeof( DDSURFACEDESC )); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; - IDirectDraw2_GetDisplayMode( p_vout->p_sys->p_ddobject, &ddsd ); - - rect_window_backup = rect_window; - - /* Clip the destination window */ - rect_window.left = (rect_window.left < 0) ? 0 : rect_window.left; - rect_window.right = (rect_window.right < 0) ? 0 : rect_window.right; - rect_window.top = (rect_window.top < 0) ? 0 : rect_window.top; - rect_window.bottom = (rect_window.bottom < 0) ? 0 : rect_window.bottom; - - rect_window.left = (rect_window.left > ddsd.dwWidth) ? ddsd.dwWidth - : rect_window.left; - rect_window.right = (rect_window.right > ddsd.dwWidth) ? ddsd.dwWidth - : rect_window.right; - rect_window.top = (rect_window.top > ddsd.dwHeight) ? ddsd.dwHeight - : rect_window.top; - rect_window.bottom = (rect_window.bottom > ddsd.dwHeight) ? ddsd.dwHeight - : rect_window.bottom; - - intf_WarnMsg( 3, "vout: DirectXUpdateOverlay window coords: %i,%i,%i,%i", - rect_window.left, rect_window.top, - rect_window.right, rect_window.bottom); - - /* the 2 following lines are to fix a bug when click on Windows desktop */ - if( (rect_window.right-rect_window.left)==0 || - (rect_window.bottom-rect_window.top)==0 ) return 0; - - /* Clip the source image */ - rect_image.left = ( rect_window.left == rect_window_backup.left ) ? 0 - : labs(rect_window_backup.left - rect_window.left) * - p_vout->p_rendered_pic->i_width / - (rect_window_backup.right - rect_window_backup.left); - rect_image.right = ( rect_window.right == rect_window_backup.right ) ? - p_vout->p_rendered_pic->i_width - : p_vout->p_rendered_pic->i_width - - labs(rect_window_backup.right - rect_window.right) * - p_vout->p_rendered_pic->i_width / - (rect_window_backup.right - rect_window_backup.left); - rect_image.top = ( rect_window.top == rect_window_backup.top ) ? 0 - : labs(rect_window_backup.top - rect_window.top) * - p_vout->p_rendered_pic->i_height / - (rect_window_backup.bottom - rect_window_backup.top); - rect_image.bottom = ( rect_window.bottom == rect_window_backup.bottom ) ? - p_vout->p_rendered_pic->i_height - : p_vout->p_rendered_pic->i_height - - labs(rect_window_backup.bottom - rect_window.bottom) * - p_vout->p_rendered_pic->i_height / - (rect_window_backup.bottom - rect_window_backup.top); - - intf_WarnMsg( 3, "vout: DirectXUpdateOverlay image coords: %i,%i,%i,%i", - rect_image.left, rect_image.top, - rect_image.right, rect_image.bottom); - - /* compute the colorkey pixel value from the RGB value we've got */ - memset( &pixel_format, 0, sizeof( DDPIXELFORMAT )); - pixel_format.dwSize = sizeof( DDPIXELFORMAT ); - dxresult = IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display, - &pixel_format ); - if( dxresult != DD_OK ) - intf_WarnMsg( 3, "vout: DirectXUpdateOverlay GetPixelFormat failed" ); - dw_colorkey = (DWORD)p_vout->p_sys->i_colorkey; -#ifdef NONAMELESSUNION - dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.u2.dwRBitMask) / 255) - & pixel_format.u2.dwRBitMask); -#else - dw_colorkey = (DWORD)((( dw_colorkey * pixel_format.dwRBitMask) / 255) - & pixel_format.dwRBitMask); -#endif + /* The new window dimensions should already have been computed by the + * caller of this function */ /* Position and show the overlay */ memset(&ddofx, 0, sizeof(DDOVERLAYFX)); ddofx.dwSize = sizeof(DDOVERLAYFX); - ddofx.dckDestColorkey.dwColorSpaceLowValue = dw_colorkey; - ddofx.dckDestColorkey.dwColorSpaceHighValue = dw_colorkey; - - dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW; - - dxresult = IDirectDrawSurface3_UpdateOverlay(p_vout->p_sys->p_surface, - &rect_image, - p_vout->p_sys->p_display, - &rect_window, - dwFlags, - &ddofx); + ddofx.dckDestColorkey.dwColorSpaceLowValue = p_vout->p_sys->i_colorkey; + ddofx.dckDestColorkey.dwColorSpaceHighValue = p_vout->p_sys->i_colorkey; + + dwFlags = DDOVER_SHOW; + if( !p_vout->p_sys->b_caps_overlay_clipping ) + dwFlags |= DDOVER_KEYDESTOVERRIDE; + + dxresult = IDirectDrawSurface3_UpdateOverlay( + p_vout->p_sys->p_current_surface, + &p_vout->p_sys->rect_src_clipped, + p_vout->p_sys->p_display, + &p_vout->p_sys->rect_dest_clipped, + dwFlags, + &ddofx ); if(dxresult != DD_OK) { intf_WarnMsg( 3, "vout: DirectXUpdateOverlay can't move or resize overlay" ); } - return ( 0 ); } /***************************************************************************** @@ -1307,10 +900,16 @@ static void DirectXCloseDDraw( vout_thread_t *p_vout ) static void DirectXCloseDisplay( vout_thread_t *p_vout ) { intf_WarnMsg( 3, "vout: DirectXCloseDisplay" ); - if( p_vout->p_sys->p_display != NULL ) + + if( p_vout->p_sys->p_clipper != NULL ) { - DirectXCloseSurface( p_vout ); + intf_WarnMsg( 3, "vout: DirectXCloseDisplay clipper" ); + IDirectDraw2_Release( p_vout->p_sys->p_clipper ); + p_vout->p_sys->p_clipper = NULL; + } + if( p_vout->p_sys->p_display != NULL ) + { intf_WarnMsg( 3, "vout: DirectXCloseDisplay display" ); IDirectDraw2_Release( p_vout->p_sys->p_display ); p_vout->p_sys->p_display = NULL; @@ -1320,126 +919,416 @@ static void DirectXCloseDisplay( vout_thread_t *p_vout ) /***************************************************************************** * DirectXCloseSurface: close the YUV overlay or RGB surface. ***************************************************************************** - * This function returns all resources allocated by the surface. - * We also call this function when the decoded picture change its dimensions - * (in that case we close the overlay surface and reopen another with the - * right dimensions). + * This function returns all resources allocated for the surface. *****************************************************************************/ -static void DirectXCloseSurface( vout_thread_t *p_vout ) +static void DirectXCloseSurface( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE3 p_surface ) { intf_WarnMsg( 3, "vout: DirectXCloseSurface" ); - if( p_vout->p_sys->p_surface != NULL ) + if( p_surface != NULL ) { - intf_WarnMsg( 3, "vout: DirectXCloseSurface surface" ); - IDirectDraw2_Release( p_vout->p_sys->p_surface ); - p_vout->p_sys->p_surface = NULL; + IDirectDraw2_Release( p_surface ); } +} - if( p_vout->p_sys->p_clipper != NULL ) +/***************************************************************************** + * NewPictureVec: allocate a vector of identical pictures + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic, + int i_num_pics ) +{ + int i; + LPDIRECTDRAWSURFACE3 p_surface; + +#if 0 + /* We couldn't use an YUV overlay so we need to indicate to video_output + * which format we are falling back to */ + switch( ) { - intf_WarnMsg( 3, "vout: DirectXCloseSurface clipper" ); - IDirectDraw2_Release( p_vout->p_sys->p_clipper ); - p_vout->p_sys->p_clipper = NULL; + case 8: /* FIXME: set the palette */ + p_vout->output.i_chroma = FOURCC_RGB2; break; + case 15: + p_vout->output.i_chroma = FOURCC_RV15; break; + case 16: + p_vout->output.i_chroma = FOURCC_RV16; break; + case 24: + p_vout->output.i_chroma = FOURCC_RV24; break; + case 32: + p_vout->output.i_chroma = FOURCC_RV32; break; + default: + intf_ErrMsg( "vout error: unknown screen depth" ); + return( 0 ); + } +#endif + + intf_WarnMsg( 3, "vout: NewPictureVec" ); + + I_OUTPUTPICTURES = 0; + + /* chroma asked for */ + p_vout->output.i_chroma = p_vout->render.i_chroma; + + /* hack */ +#if 1 + if( p_vout->render.i_chroma == FOURCC_I420 ) + p_vout->output.i_chroma = FOURCC_YV12; +#endif + + /* First we try to create an overlay surface. + * It looks like with most hardware it's not possible to create several + * overlay surfaces, and even if it was I bet it would be slower anyway to + * use them as direct buffers because they usually reside in video memory + * which is quite slow. + * So the overlay surface (with a back-buffer) that we create won't be used + * to decode directly into it but instead picture buffers in system memory + * will be blitted to it. */ + if( p_vout->p_sys->b_using_overlay ) + { + if( DirectXCreateSurface( p_vout, &p_surface, p_vout->output.i_chroma, + p_vout->p_sys->b_using_overlay ) ) + { + DDSCAPS dds_caps; + + /* Allocate internal structure */ + p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) ); + if( p_pic[0].p_sys == NULL ) + { + DirectXCloseSurface( p_vout, p_surface ); + return -1; + } + + /* set front buffer */ + p_pic[0].p_sys->p_front_surface = p_surface; + + /* Get the back buffer */ + memset( &dds_caps, 0, sizeof( DDSCAPS )); + dds_caps.dwCaps = DDSCAPS_BACKBUFFER; + if( DD_OK != IDirectDrawSurface3_GetAttachedSurface( + p_surface, &dds_caps, + &p_pic[0].p_sys->p_surface ) ) + { + intf_WarnMsg( 3, "vout: NewPictureVec couldn't get " + "back buffer" ); + /* front buffer is the same as back buffer */ + p_pic[0].p_sys->p_surface = p_surface; + } + + + p_vout->p_sys->p_current_surface= p_pic[0].p_sys->p_front_surface; + DirectXUpdateOverlay( p_vout ); + I_OUTPUTPICTURES = 1; + } + else p_vout->p_sys->b_using_overlay = 0; + } + + /* As we can't have overlays, we'll try to create plain RBG surfaces in + * system memory. These surfaces will then be blitted onto the primary + * surface (display) so they can be displayed */ + if( !p_vout->p_sys->b_using_overlay ) + { + /* FixMe */ + p_vout->output.i_chroma = FOURCC_RV16; + p_vout->output.i_rmask = 0x001f; + p_vout->output.i_gmask = 0x03e0; + p_vout->output.i_bmask = 0x7c00; + + for( i = 0; i < i_num_pics; i++ ) + { + if( DirectXCreateSurface( p_vout, &p_surface, + p_vout->output.i_chroma, + p_vout->p_sys->b_using_overlay ) ) + { + /* Allocate internal structure */ + p_pic[i].p_sys = malloc( sizeof( picture_sys_t ) ); + if( p_pic[i].p_sys == NULL ) + { + DirectXCloseSurface( p_vout, p_surface ); + FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES ); + I_OUTPUTPICTURES = 0; + return -1; + } + p_pic[i].p_sys->p_surface = p_surface; + p_pic[i].p_sys->p_front_surface = NULL; + I_OUTPUTPICTURES++; + + } + else break; + } + } + + + /* Now that we've got all our direct-buffers, we can finish filling in the + * picture_t structures */ + for( i = 0; i < I_OUTPUTPICTURES; i++ ) + { + p_pic[i].i_status = DESTROYED_PICTURE; + p_pic[i].i_type = DIRECT_PICTURE; + PP_OUTPUTPICTURE[i] = &p_pic[i]; + + if( !DirectXGetSurfaceDesc( &p_pic[i] ) ) + { + /* AAARRGG */ + FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES ); + I_OUTPUTPICTURES = 0; + return -1; + } + + if( !UpdatePictureStruct(p_vout, &p_pic[i], p_vout->output.i_chroma) ) + { + + /* Unknown chroma, tell the guy to get lost */ + intf_ErrMsg( "vout error: never heard of chroma 0x%.8x (%4.4s)", + p_vout->output.i_chroma, + (char*)&p_vout->output.i_chroma ); + FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES ); + I_OUTPUTPICTURES = 0; + return -1; + } } - /* Disable any display */ - p_vout->p_sys->b_display_enabled = 0; + intf_WarnMsg( 3, "vout: End NewPictureVec"); + return 0; } /***************************************************************************** - * DirectXKeepAspectRatio: + * FreePicture: destroy a picture vector allocated with NewPictureVec ***************************************************************************** - * This function adjusts the coordinates of the video rectangle to keep the - * aspect/ratio of the video. + * *****************************************************************************/ -static void DirectXKeepAspectRatio( vout_thread_t *p_vout, RECT *rect_window ) +static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic, + int i_num_pics ) { + int i; - if( !p_vout->p_rendered_pic ) return; - - switch( p_vout->p_rendered_pic->i_aspect_ratio ) - { - case AR_16_9_PICTURE: - if( ((rect_window->right-rect_window->left)*9) - > ((rect_window->bottom-rect_window->top)*16) ) - { - int temp; - temp = (rect_window->bottom-rect_window->top)*16/9; - temp = (rect_window->right-rect_window->left) - temp; - rect_window->left += (temp/2); - rect_window->right -= (temp/2); - } - else + for( i = 0; i < i_num_pics; i++ ) + { +#if 0 + if( p_pic->p_sys->p_front_surface && + ( p_pic->p_sys->p_surface != p_pic->p_sys->p_front_surface ) ) + DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface ); +#endif + + DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_surface ); + + for( i = 0; i < i_num_pics; i++ ) { - int temp; - temp = (rect_window->right-rect_window->left)*9/16; - temp = (rect_window->bottom-rect_window->top) - temp; - rect_window->top += (temp/2); - rect_window->bottom -= (temp/2); + free( p_pic[i].p_sys ); } - break; - - case AR_221_1_PICTURE: - if( ((rect_window->right-rect_window->left)*100) - > ((rect_window->bottom-rect_window->top)*221) ) - { - int temp; - temp = (rect_window->bottom-rect_window->top)*221/100; - temp = (rect_window->right-rect_window->left) - temp; - rect_window->left += (temp/2); - rect_window->right -= (temp/2); - } - else - { - int temp; - temp = (rect_window->right-rect_window->left)*100/221; - temp = (rect_window->bottom-rect_window->top) - temp; - rect_window->top += (temp/2); - rect_window->bottom -= (temp/2); - } - break; - - case AR_3_4_PICTURE: - if( ((rect_window->right-rect_window->left)*3) - > ((rect_window->bottom-rect_window->top)*4) ) - { - int temp; - temp = (rect_window->bottom-rect_window->top)*4/3; - temp = (rect_window->right-rect_window->left) - temp; - rect_window->left += (temp/2); - rect_window->right -= (temp/2); - } - else - { - int temp; - temp = (rect_window->right-rect_window->left)*3/4; - temp = (rect_window->bottom-rect_window->top) - temp; - rect_window->top += (temp/2); - rect_window->bottom -= (temp/2); - } - break; - - case AR_SQUARE_PICTURE: - default: - if( (rect_window->right-rect_window->left) - > (rect_window->bottom-rect_window->top) ) - { - int temp; - temp = (rect_window->bottom-rect_window->top); - temp = (rect_window->right-rect_window->left) - temp; - rect_window->left += (temp/2); - rect_window->right -= (temp/2); - } + } +} + +/***************************************************************************** + * UpdatePictureStruct: updates the internal data in the picture_t structure + ***************************************************************************** + * This will setup stuff for use by the video_output thread + *****************************************************************************/ +static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic, + int i_chroma ) +{ + + switch( p_vout->output.i_chroma ) + { + + case FOURCC_YV12: + + p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface; + p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch; + p_pic->p[Y_PLANE].i_pixel_bytes = 1; + p_pic->p[Y_PLANE].b_margin = 0; + + p_pic->V_PIXELS = p_pic->Y_PIXELS + + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch; + p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[V_PLANE].i_pixel_bytes = 1; + p_pic->p[V_PLANE].b_margin = 0; + + p_pic->U_PIXELS = p_pic->V_PIXELS + + p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch; + p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[U_PLANE].i_pixel_bytes = 1; + p_pic->p[U_PLANE].b_margin = 0; + + p_pic->i_planes = 3; + break; + + case FOURCC_RV16: + + p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch; + p_pic->p->i_pixel_bytes = 2; + p_pic->p->b_margin = 0; + + p_pic->i_planes = 1; + break; + + case FOURCC_RV15: + + p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch; + p_pic->p->i_pixel_bytes = 2; + p_pic->p->b_margin = 0; + + p_pic->i_planes = 1; + break; + + case FOURCC_I420: + + p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface; + p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch; + p_pic->p[Y_PLANE].i_pixel_bytes = 1; + p_pic->p[Y_PLANE].b_margin = 0; + + p_pic->U_PIXELS = p_pic->Y_PIXELS + + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch; + p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[U_PLANE].i_pixel_bytes = 1; + p_pic->p[U_PLANE].b_margin = 0; + + p_pic->V_PIXELS = p_pic->U_PIXELS + + p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch; + p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[V_PLANE].i_pixel_bytes = 1; + p_pic->p[V_PLANE].b_margin = 0; + + p_pic->i_planes = 3; + break; + +#if 0 + case FOURCC_Y211: + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p->i_lines = p_vout->output.i_height; + /* XXX: this just looks so plain wrong... check it out ! */ + p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4; + p_pic->p->i_pixel_bytes = 4; + p_pic->p->b_margin = 0; + + p_pic->i_planes = 1; + break; + + case FOURCC_YUY2: + case FOURCC_UYVY: + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0]; + p_pic->p->i_pixel_bytes = 4; + p_pic->p->b_margin = 0; + + p_pic->i_planes = 1; + break; +#endif + + default: + /* Not supported */ + return 0; + + } + + return 1; +} + +/***************************************************************************** + * DirectXGetDDrawCaps: Probe the capabilities of the hardware + ***************************************************************************** + * It is nice to know which features are supported by the hardware so we can + * find ways to optimize our rendering. + *****************************************************************************/ +static void DirectXGetDDrawCaps( vout_thread_t *p_vout ) +{ + DDCAPS ddcaps; + HRESULT dxresult; + + /* This is just an indication of whether or not we'll support overlay, + * but with this test we don't know if we support YUV overlay */ + memset( &ddcaps, 0, sizeof( DDCAPS )); + ddcaps.dwSize = sizeof(DDCAPS); + dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject, + &ddcaps, NULL ); + if(dxresult != DD_OK ) + { + intf_WarnMsg( 3,"vout error: can't get caps." ); + } else - { - int temp; - temp = (rect_window->right-rect_window->left); - temp = (rect_window->bottom-rect_window->top) - temp; - rect_window->top += (temp/2); - rect_window->bottom -= (temp/2); - } - break; - - } + { + BOOL bHasOverlay, bHasOverlayFourCC, bCanClipOverlay, + bHasColorKey, bCanStretch; + + /* Determine if the hardware supports overlay surfaces */ + bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) == + DDCAPS_OVERLAY) ? TRUE : FALSE; + /* Determine if the hardware supports overlay surfaces */ + bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) == + DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE; + /* Determine if the hardware supports overlay surfaces */ + bCanClipOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) == + 0 ) ? TRUE : FALSE; + /* Determine if the hardware supports colorkeying */ + bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) == + DDCAPS_COLORKEY) ? TRUE : FALSE; + /* Determine if the hardware supports scaling of the overlay surface */ + bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) == + DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE; + intf_WarnMsg( 3, "vout: DirectDraw Capabilities:" ); + intf_WarnMsg( 3, " overlay=%i yuvoverlay=%i can_clip_overlay=%i " + "colorkey=%i stretch=%i", + bHasOverlay, bHasOverlayFourCC, bCanClipOverlay, + bHasColorKey, bCanStretch ); + + /* Overlay clipping support is interesting for us as it means we can + * get rid of the colorkey alltogether */ + p_vout->p_sys->b_caps_overlay_clipping = bCanClipOverlay; + + } +} + +/***************************************************************************** + * DirectXGetSurfaceDesc: Get some more information about the surface + ***************************************************************************** + * This function get and stores the surface descriptor which among things + * has the pointer to the picture data. + *****************************************************************************/ +static int DirectXGetSurfaceDesc( picture_t *p_pic ) +{ + HRESULT dxresult; + + /* Lock the surface to get a valid pointer to the picture buffer */ + memset( &p_pic->p_sys->ddsd, 0, sizeof( DDSURFACEDESC )); + p_pic->p_sys->ddsd.dwSize = sizeof(DDSURFACEDESC); + dxresult = IDirectDrawSurface3_Lock( p_pic->p_sys->p_surface, + NULL, &p_pic->p_sys->ddsd, + DDLOCK_NOSYSLOCK, + NULL ); + if ( dxresult == DDERR_SURFACELOST ) + { + /* Your surface can be lost so be sure + * to check this and restore it if needed */ + dxresult = IDirectDrawSurface3_Restore( p_pic->p_sys->p_surface ); + dxresult = IDirectDrawSurface3_Lock( p_pic->p_sys->p_surface, NULL, + &p_pic->p_sys->ddsd, + DDLOCK_NOSYSLOCK | DDLOCK_WAIT, + NULL); + } + if( dxresult != DD_OK ) + { + intf_ErrMsg( "vout: DirectXGetSurfaceDesc can't lock surface" ); + return 0; + } + + /* Unlock the Surface */ + dxresult = IDirectDrawSurface3_Unlock( p_pic->p_sys->p_surface, NULL ); + return 1; }