DirectX plugins
Gildas Bazin
gbazin at netcourrier.com
Fri May 18 04:29:21 CEST 2001
I hope this time Listar will accept them.
>
>
>
>
> -- Binary/unsupported file stripped by Listar --
> -- Type: text/x-c
>
>
> -- Binary/unsupported file stripped by Listar --
> -- Type: text/x-makefile
>
>
> -- Binary/unsupported file stripped by Listar --
> -- Type: text/x-c
>
>
> -- Binary/unsupported file stripped by Listar --
> -- Type: text/x-c
>
>
>
>
-- Attached file included as plaintext by Listar --
###############################################################################
# vlc (VideoLAN Client) sdl module Makefile
# (c)2001 VideoLAN
###############################################################################
#
# Objects
#
PLUGIN_C = windx.o vout_windx.o aout_windx.o
BUILTIN_C = $(PLUGIN_C:%.o=BUILTIN_%.o)
ALL_OBJ = $(PLUGIN_C) $(BUILTIN_C)
#
# Virtual targets
#
include ../../Makefile.modules
#
# Real targets
#
./../lib/windx.so: $(PLUGIN_C)
$(CC) $(PCFLAGS) -o $@ $^ $(PLCFLAGS) $(LIB_SDL)
./../lib/windx.a: $(BUILTIN_C)
ar r $@ $^
$(RANLIB) $@
-- Attached file included as plaintext by Listar --
/*****************************************************************************
* aout_sdl.c : audio sdl functions library
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: aout_sdl.c,v 1.12 2001/04/28 03:36:25 sam Exp $
*
* Authors: Gildas Bazin <gbazin at netcourrier.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#define MODULE_NAME windx
#include "modules_inner.h"
/* The most important this to do for now is to fix the audio bug we've got
* on startup: the audio will start later than the video (sometimes) and
* is trying to catching up with it.
* At first sight it seems to be a scheduling problem
*/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include "defs.h"
#include <errno.h> /* ENOMEM */
#include <fcntl.h> /* open(), O_WRONLY */
#include <string.h> /* strerror() */
#include <unistd.h> /* write(), close() */
#include <stdio.h> /* "intf_msg.h" */
#include <stdlib.h> /* calloc(), malloc(), free() */
#include "config.h"
#include "common.h" /* boolean_t, byte_t */
#include "threads.h"
#include "mtime.h"
#include "tests.h"
#include "directx.h"
#include "audio_output.h" /* aout_thread_t */
#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
#include "main.h"
#include "modules.h"
/*****************************************************************************
* aout_sys_t: windx audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the direct sound specific properties of an audio device.
*****************************************************************************/
typedef struct aout_sys_s
{
LPDIRECTSOUND p_dsobject; /* main Direct Sound object */
LPDIRECTSOUNDBUFFER p_dsbuffer_primary; /* the actual sound card buffer
(not used directly) */
LPDIRECTSOUNDBUFFER p_dsbuffer; /* the sound buffer we use (direct sound
* takes care of mixing all the
* secondary buffers into the primary) */
long l_buffer_size; /* secondary sound buffer size */
long l_write_position; /* next write position for the buffer */
boolean_t b_active;
} aout_sys_t;
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static int aout_Probe ( probedata_t *p_data );
static int aout_Open ( aout_thread_t *p_aout );
static int aout_SetFormat ( aout_thread_t *p_aout );
static long aout_GetBufInfo ( aout_thread_t *p_aout, long l_buffer_info );
static void aout_Play ( aout_thread_t *p_aout,
byte_t *buffer, int i_size );
static void aout_Close ( aout_thread_t *p_aout );
/* local function */
static int windx_CreateSecondaryBuffer( aout_thread_t *p_aout );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
void _M( aout_getfunctions )( function_list_t * p_function_list )
{
p_function_list->pf_probe = aout_Probe;
p_function_list->functions.aout.pf_open = aout_Open;
p_function_list->functions.aout.pf_setformat = aout_SetFormat;
p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
p_function_list->functions.aout.pf_play = aout_Play;
p_function_list->functions.aout.pf_close = aout_Close;
}
/*****************************************************************************
* aout_Probe: probe the audio device and return a score
*****************************************************************************
* This function tries to probe for a Direct Sound device and returns a
* score to the plugin manager so that it can select the best plugin.
*****************************************************************************/
static int aout_Probe( probedata_t *p_data )
{
intf_WarnMsg( 3, "aout: WinDX aout_Probe");
/* For now just assume the computer has a sound device */
if( TestMethod( AOUT_METHOD_VAR, "windx" ) )
{
return( 999 );
}
return( 400 );
}
/*****************************************************************************
* aout_Open: open the audio device
*****************************************************************************
* This function opens and setups Direct Sound.
*****************************************************************************/
static int aout_Open( aout_thread_t *p_aout )
{
#if 0
HRESULT dsresult;
DSBUFFERDESC dsbuffer_desc;
WAVEFORMATEX waveformat;
#endif
intf_WarnMsg( 3, "aout: WinDX aout_Open");
/* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL )
{
intf_ErrMsg( "aout error: %s", strerror(ENOMEM) );
return( 1 );
}
/* Initialize some variables */
p_aout->p_sys->p_dsobject = NULL;
p_aout->p_sys->p_dsbuffer_primary = NULL;
p_aout->p_sys->p_dsbuffer = NULL;
p_aout->psz_device = 0;
p_aout->i_format = AOUT_FORMAT_DEFAULT;
p_aout->i_channels = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
AOUT_STEREO_DEFAULT );
p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR,
AOUT_RATE_DEFAULT );
/* Create the direct sound object */
if( DirectSoundCreate(NULL, &p_aout->p_sys->p_dsobject, NULL) != DS_OK )
{
intf_WarnMsg( 3, "aout: can't create a direct sound device ");
p_aout->p_sys->p_dsobject = NULL;
return( 1 );
}
/* Set DirectSound Cooperative level, ie what control we want over Windows
* sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
* settings of the primary buffer, but also that only the sound of our
* application will be hearable when it will have the focus.
* !!! (this is not really working as intended yet because to set the
* cooperative level you need the window handle of your application, and
* I don't know of any easy way to get it. Especially since we might play
* sound without any video, and so what window handle should we use ???
* The hack for now is to use the Desktop window handle - it seems to be
* working */
if( IDirectSound_SetCooperativeLevel(p_aout->p_sys->p_dsobject,
GetDesktopWindow(),
DSSCL_EXCLUSIVE) )
{
intf_WarnMsg( 3, "aout: can't set direct sound cooperative level ");
}
#if 0
/* Obtain (not create) Direct Sound primary buffer */
memset( &dsbuffer_desc, 0, sizeof(DSBUFFERDESC) );
dsbuffer_desc.dwSize = sizeof(DSBUFFERDESC);
dsbuffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER;
intf_WarnMsg( 3, "aout: Create direct sound primary buffer ");
dsresult = IDirectSound_CreateSoundBuffer(p_aout->p_sys->p_dsobject,
&dsbuffer_desc,
&p_aout->p_sys->p_dsbuffer_primary,
NULL);
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: can't create direct sound primary buffer ");
IDirectSound_Release( p_aout->p_sys->p_dsobject );
p_aout->p_sys->p_dsobject = NULL;
p_aout->p_sys->p_dsbuffer_primary = NULL;
return( 1 );
}
/* Set Direct Sound primary buffer format because the default value set by
* Windows is usually not the high quality value */
memset(&waveformat, 0, sizeof(WAVEFORMATEX));
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = 2;
waveformat.nSamplesPerSec = 44100;
waveformat.wBitsPerSample = 16;
waveformat.nBlockAlign = waveformat.wBitsPerSample / 8 *
waveformat.nChannels;
waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec *
waveformat.nBlockAlign;
dsresult = IDirectSoundBuffer_SetFormat(p_aout->p_sys->p_dsbuffer_primary,
&waveformat);
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: can't set primary buffer format");
}
/* ensure the primary buffer is playing. We won't actually hear anything
* until the secondary buffer is playing */
dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer_primary,
0,
0,
DSBPLAY_LOOPING);
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: can't play direct sound primary buffer ");
IDirectSound_Release( p_aout->p_sys->p_dsbuffer_primary );
IDirectSound_Release( p_aout->p_sys->p_dsobject );
p_aout->p_sys->p_dsobject = NULL;
p_aout->p_sys->p_dsbuffer_primary = NULL;
return( 1 );
}
#endif
/* Now create the buffer that we'll actually use: the secondary buffer */
if( windx_CreateSecondaryBuffer( p_aout ) )
{
intf_WarnMsg( 3, "aout: can't create direct sound secondary buffer ");
#if 0
IDirectSound_Release( p_aout->p_sys->p_dsbuffer_primary );
#endif
IDirectSound_Release( p_aout->p_sys->p_dsobject );
p_aout->p_sys->p_dsobject = NULL;
p_aout->p_sys->p_dsbuffer_primary = NULL;
p_aout->p_sys->p_dsbuffer = NULL;
return( 1 );
}
intf_WarnMsg( 3, "aout: End aout_Create ");
return( 0 );
}
/*****************************************************************************
* aout_SetFormat: reset the audio device and sets its format
*****************************************************************************
* This functions set a new audio format.
* For this we need to close the current secondary buffer and create another
* one with the desired format.
*****************************************************************************/
static int aout_SetFormat( aout_thread_t *p_aout )
{
HRESULT dsresult;
intf_WarnMsg( 3, "aout: WinDX aout_SetFormat");
/* first release the current secondary buffer */
if( p_aout->p_sys->p_dsbuffer != NULL )
{
IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer );
p_aout->p_sys->p_dsbuffer = NULL;
}
/* then create a new secondary buffer */
dsresult = windx_CreateSecondaryBuffer( p_aout );
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: WinDX aout_SetFormat cannot create buffer");
return( 1 );
}
return( 0 );
}
/*****************************************************************************
* aout_GetBufInfo: buffer status query
*****************************************************************************
* returns the number of bytes in the audio buffer compared to the size of
* l_buffer_limit...
*****************************************************************************/
static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
{
long l_play_position, l_notused, l_result;
HRESULT dsresult;
dsresult = IDirectSoundBuffer_GetCurrentPosition(p_aout->p_sys->p_dsbuffer,
&l_play_position, &l_notused);
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_GetCurrentPosition(
p_aout->p_sys->p_dsbuffer,
&l_play_position, &l_notused
);
}
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: WinDX aout_GetBufInfo cannot get current pos");
return( l_buffer_limit );
}
l_result = ((p_aout->p_sys->l_write_position >= l_play_position) ?
(p_aout->p_sys->l_write_position - l_play_position)/2
: (p_aout->p_sys->l_buffer_size - l_play_position
+ p_aout->p_sys->l_write_position)/2 );
intf_WarnMsg( 5, "aout: WinDX aout_GetBufInfo: %li", l_result);
return l_result;
}
/*****************************************************************************
* aout_Play: play a sound buffer
*****************************************************************************
* This function writes a buffer of i_length bytes
*****************************************************************************/
static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
{
VOID *p_write_position, *p_start_buffer;
long l_bytes1, l_bytes2;
long l_play_position, l_notused, l_buffer_free_length;
HRESULT dsresult;
intf_WarnMsg( 6, "aout: WinDX aout_Play");
/* We want to copy data to the circular sound buffer, so first we need to
* find out were in the buffer we can write our data */
dsresult = IDirectSoundBuffer_GetCurrentPosition(p_aout->p_sys->p_dsbuffer,
&l_play_position,
&l_notused);
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_GetCurrentPosition(
p_aout->p_sys->p_dsbuffer,
&l_play_position, &l_notused
);
}
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: WinDX aout_Play can'get buffer position");
}
/* check that we are not overflowing the circular buffer (everything should
* be alright but just in case) */
l_buffer_free_length = l_play_position - p_aout->p_sys->l_write_position;
if( l_buffer_free_length <= 0 )
l_buffer_free_length += p_aout->p_sys->l_buffer_size ;
if( i_size > l_buffer_free_length )
{
intf_WarnMsg( 3, "aout: WinDX aout_Play buffer overflow: size %i, free %i !!!", i_size, l_buffer_free_length);
intf_WarnMsg( 3, "aout: WinDX aout_Play buffer overflow: writepos %i, readpos %i !!!", l_play_position, p_aout->p_sys->l_write_position);
/*i_size = l_buffer_free_length;*/
}
/* Before copying anything, we have to lock the buffer */
dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
p_aout->p_sys->l_write_position, /* Offset of lock start */
i_size, /* Number of bytes to lock */
&p_write_position, /* Address of lock start */
&l_bytes1, /* Count of bytes locked before wrap around */
&p_start_buffer, /* Buffer adress (if wrap around) */
&l_bytes2, /* Count of bytes after wrap around */
0); /* Flags */
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
p_aout->p_sys->l_write_position,
i_size,
&p_write_position,
&l_bytes1,
&p_start_buffer,
&l_bytes2,
0);
}
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: WinDX aout_Play can't lock buffer");
return;
}
/* Now do the actual memcopy (two memcpy because the buffer is circular) */
memcpy( p_write_position, buffer, l_bytes1 );
if( p_start_buffer != NULL )
memcpy( p_start_buffer, buffer + l_bytes1, l_bytes2 );
/* Now the data has been copied, unlock the buffer */
IDirectSoundBuffer_Unlock( p_aout->p_sys->p_dsbuffer,
p_write_position, l_bytes1, p_start_buffer, l_bytes2 );
/* Update the write position index of the buffer*/
p_aout->p_sys->l_write_position += i_size;
p_aout->p_sys->l_write_position %= p_aout->p_sys->l_buffer_size;
/* The play function has no effect if the buffer is already playing */
dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer,
0, /* Unused */
0, /* Unused */
DSBPLAY_LOOPING ); /* Flags */
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer,
0, /* Unused */
0, /* Unused */
DSBPLAY_LOOPING ); /* Flags */
}
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: WinDX aout_Play can't play buffer");
return;
}
}
/*****************************************************************************
* aout_Close: close the audio device
*****************************************************************************/
static void aout_Close( aout_thread_t *p_aout )
{
intf_WarnMsg( 3, "aout: WinDX aout_Close");
/* make sure the buffer isn't playing */
if( p_aout->p_sys->p_dsbuffer != NULL )
{
IDirectSoundBuffer_Stop( p_aout->p_sys->p_dsbuffer );
}
/* first release the secondary buffer */
if( p_aout->p_sys->p_dsbuffer != NULL )
{
IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer );
p_aout->p_sys->p_dsbuffer = NULL;
}
/* then release the primary buffer */
if( p_aout->p_sys->p_dsbuffer_primary != NULL )
{
IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer_primary );
p_aout->p_sys->p_dsbuffer_primary = NULL;
}
/* finally release the DirectSound object */
if( p_aout->p_sys->p_dsobject != NULL )
{
IDirectSound_Release( p_aout->p_sys->p_dsobject );
p_aout->p_sys->p_dsobject = NULL;
}
/* Close the Output. */
if ( p_aout->p_sys != NULL )
{
free( p_aout->p_sys );
p_aout->p_sys = NULL;
}
}
/*****************************************************************************
* windx_CreateSecondaryBuffer
*****************************************************************************
* This function creates the buffer we'll use to play audio.
* In DirectSound there are two kinds of buffers:
* - the primary buffer: which is the actual buffer that the soundcard plays
* - the secondary buffer(s): these buffers are the one actually used by
* applications and DirectSound takes care of mixing them into the primary.
*
* Once you create a secondary buffer, you cannot change its format anymore so
* you have to release the current and create another one.
*****************************************************************************/
static int windx_CreateSecondaryBuffer( aout_thread_t *p_aout )
{
WAVEFORMATEX waveformat;
DSBUFFERDESC dsbdesc;
DSBCAPS dsbcaps;
HRESULT dsresult;
intf_WarnMsg( 3, "aout: WinDX WinDX_CreateSecondaryBuffer");
/* First set the buffer format */
memset(&waveformat, 0, sizeof(WAVEFORMATEX));
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = p_aout->i_channels;
waveformat.nSamplesPerSec = p_aout->l_rate;
waveformat.wBitsPerSample = 16;
waveformat.nBlockAlign = waveformat.wBitsPerSample / 8 *
waveformat.nChannels;
waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec *
waveformat.nBlockAlign;
/* Then fill in the descriptor */
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
| DSBCAPS_GLOBALFOCUS; /* Allows background playing */
/* | DSBCAPS_CTRLPAN
| DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLFREQUENCY;
*/
dsbdesc.dwBufferBytes = waveformat.nAvgBytesPerSec * 4; /* 4 sec buffer */
dsbdesc.lpwfxFormat = &waveformat;
intf_WarnMsg( 3, "aout: Create direct sound secondary buffer ");
if( IDirectSound_CreateSoundBuffer( p_aout->p_sys->p_dsobject,
&dsbdesc,
&p_aout->p_sys->p_dsbuffer,
NULL) != DS_OK )
{
intf_WarnMsg( 3, "aout: can't create direct sound secondary buffer ");
p_aout->p_sys->p_dsbuffer = NULL;
return( 1 );
}
/* backup the size of the secondary sound buffer */
memset(&dsbcaps, 0, sizeof(DSBCAPS));
dsbcaps.dwSize = sizeof(DSBCAPS);
IDirectSoundBuffer_GetCaps( p_aout->p_sys->p_dsbuffer, &dsbcaps );
p_aout->p_sys->l_buffer_size = dsbcaps.dwBufferBytes;
p_aout->p_sys->l_write_position = 0;
intf_WarnMsg( 3, "aout: WinDX WinDX_CreateSecondaryBuffer: %li",
p_aout->p_sys->l_buffer_size);
/* make sure the buffer isn't playing */
IDirectSoundBuffer_Stop( p_aout->p_sys->p_dsbuffer );
/* reset play position, just to be sure (and after some tests it seems
* indeed necessary */
dsresult = IDirectSoundBuffer_SetCurrentPosition(p_aout->p_sys->p_dsbuffer,
0 );
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_SetCurrentPosition(
p_aout->p_sys->p_dsbuffer,
0 );
}
if( dsresult != DS_OK )
{
intf_WarnMsg( 3, "aout: WinDX CreateSecondary cannot wet current pos");
}
return( 0 );
}
-- Attached file included as plaintext by Listar --
/*****************************************************************************
* vout_windx.c: Windows DirectX video output display method
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: vout_windx.c,v 1.00 2001/04/28 03:36:25 sam Exp $
*
* Authors: Gildas Bazin <gbazin at netcourrier.com>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#define MODULE_NAME windx
#include "modules_inner.h"
/* This is a list of what needs to be fixed:
*
* For now, this plugin only works when YUV overlay is supported (which it
* should be nowadays on most of the video cards under Windows)...
*
* The overlay doesn't use double-buffering.
*
* Use Shane Harper's optimizations for YUV
*/
/*****************************************************************************
* Preamble
*
*****************************************************************************/
#include "defs.h"
#include <errno.h> /* ENOMEM */
#include <stdlib.h> /* free() */
#include <string.h> /* strerror() */
#include <windows.h>
#include <directx.h>
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
#include "tests.h"
#include "modules.h"
#include "video.h"
#include "video_output.h"
#include "intf_msg.h"
#include "interface.h"
#include "main.h"
#include "netutils.h"
#define OVERLAY_COLOR_KEY 1 /* color on top of which the overlay will be
* displayed. 1 should be almost black but
* not black (which is too common a color) */
/*****************************************************************************
* vout_sys_t: video output DirectX method descriptor
*****************************************************************************
* This structure is part of the video output thread descriptor.
* It describes the DirectX specific properties of an output thread.
*****************************************************************************/
typedef struct vout_sys_s
{
LPDIRECTDRAW p_ddobject; /* DirectDraw object */
LPDIRECTDRAWSURFACE p_display; /* display device */
LPDIRECTDRAWSURFACE p_overlay; /* overlay device */
LPDIRECTDRAWCLIPPER p_clipper; /* clipper */
HWND hwnd; /* Handle of the main */
/* window */
int i_image_width; /* size of the decoded image */
int i_image_height;
int i_window_width; /* size of the displayed image */
int i_window_height;
boolean_t b_display_enabled;
boolean_t b_overlay;
boolean_t b_cursor;
boolean_t b_cursor_autohidden;
mtime_t i_lastmoved;
char *p_windx_buf[2]; /* Buffer information */
} vout_sys_t;
/*****************************************************************************
* 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 WinDXCreateWindow ( vout_thread_t *p_vout );
static int WinDXInitDDraw ( vout_thread_t *p_vout );
static int WinDXCreateDisplay ( vout_thread_t *p_vout );
static int WinDXCreateYUVOverlay ( vout_thread_t *p_vout );
static int WinDXUpdateOverlay ( vout_thread_t *p_vout );
static int WinDXClipOverlay ( vout_thread_t *p_vout );
static void WinDXCloseDDraw ( vout_thread_t *p_vout );
static void WinDXCloseWindow ( vout_thread_t *p_vout );
static void WinDXCloseDisplay ( vout_thread_t *p_vout );
static void WinDXCloseYUVOverlay ( vout_thread_t *p_vout );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
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_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 )
{
intf_WarnMsg( 3, "vout: WinDX vout_Probe" );
if( TestMethod( VOUT_METHOD_VAR, "windx" ) )
{
return( 999 );
}
return( 400 );
}
/*****************************************************************************
* vout_Create: allocate DirectX video thread output method
*****************************************************************************
* This function allocates and initialize the DirectX vout method.
*****************************************************************************/
static int vout_Create( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: WinDX vout_Create" );
/* Allocate structure */
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
if( p_vout->p_sys == NULL )
{
intf_ErrMsg( "vout error: can't create p_sys (%s)", strerror(ENOMEM) );
return( 1 );
}
p_vout->p_sys->b_cursor = 1; /* TODO should be done with a main_GetInt.. */
p_vout->p_sys->b_cursor_autohidden = 0;
p_vout->p_sys->b_display_enabled = 0;
p_vout->p_sys->i_lastmoved = mdate();
p_vout->b_fullscreen = main_GetIntVariable( VOUT_FULLSCREEN_VAR,
VOUT_FULLSCREEN_DEFAULT );
p_vout->p_sys->b_overlay = main_GetIntVariable( VOUT_OVERLAY_VAR,
VOUT_OVERLAY_DEFAULT );
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;
/* Create a window for the video */
/* Creating a window under Windows also initializes the thread's event
* message qeue */
if( WinDXCreateWindow( p_vout ) )
{
intf_ErrMsg( "vout error: can't create window" );
free( p_vout->p_sys );
return ( 1 );
}
/* Initialise DirectDraw */
if( WinDXInitDDraw( p_vout ) )
{
intf_ErrMsg( "vout error: can't initialise DirectDraw" );
WinDXCloseWindow( p_vout );
free( p_vout->p_sys );
return ( 1 );
}
/* create the directx display */
if( WinDXCreateDisplay( p_vout ) )
{
intf_ErrMsg( "vout error: can't initialise DirectDraw" );
WinDXCloseDDraw( p_vout );
WinDXCloseWindow( p_vout );
free( p_vout->p_sys );
return ( 1 );
}
intf_WarnMsg( 3, "vout: WinDX End vout_Create" );
return( 0 );
}
/*****************************************************************************
* vout_Init: initialize DirectX video thread output method
*****************************************************************************
*
*****************************************************************************/
static int vout_Init( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: WinDX vout_Init" );
return( 0 );
}
/*****************************************************************************
* vout_End: terminate Sys video thread output method
*****************************************************************************
* Terminate an output method created by vout_Create.
* It is called at the end of the thread.
*****************************************************************************/
static void vout_End( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: WinDX vout_End" );
}
/*****************************************************************************
* vout_Destroy: destroy Sys video thread output method
*****************************************************************************
* Terminate an output method created by vout_Create
*****************************************************************************/
static void vout_Destroy( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: WinDX vout_Destroy" );
WinDXCloseDisplay( p_vout );
WinDXCloseDDraw( p_vout );
WinDXCloseWindow( p_vout );
if( p_vout->p_sys != NULL )
{
free( p_vout->p_sys );
p_vout->p_sys = NULL;
}
}
/*****************************************************************************
* 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.
*****************************************************************************/
static int vout_Manage( vout_thread_t *p_vout )
{
MSG msg;
WINDOWPLACEMENT window_placement;
intf_WarnMsg( 4, "vout: WinDX vout_Manage" );
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if( GetMessage(&msg, NULL, 0, 0) >= 0 )
{
switch( msg.message )
{
case WM_QUIT:
intf_WarnMsg( 3, "vout: WinDX vout_Manage WM_QUIT" );
p_main->p_intf->b_die = 1;
break;
case WM_MOVE:
intf_WarnMsg( 3, "vout: WinDX vout_Manage WM_MOVE" );
if( !p_vout->b_need_render )
{
WinDXUpdateOverlay( p_vout );
}
/* don't create a never ending loop */
return( 0 );
break;
case WM_PAINT:
intf_WarnMsg( 3, "vout: WinDX vout_Manage WM_PAINT" );
if( !p_vout->b_need_render )
{
WinDXClipOverlay( p_vout );
}
/* don't create a never ending loop */
return( 0 );
break;
case WM_CHAR:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_CHAR" );
switch( msg.wParam )
{
case 'q':
case 'Q':
p_main->p_intf->b_die = 1;
break;
case 'f':
case 'F':
p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
break;
case '0':
network_ChannelJoin( 0 );
break;
case '1':
network_ChannelJoin( 1 );
break;
case '2':
network_ChannelJoin( 2 );
break;
case '3':
network_ChannelJoin( 3 );
break;
case '4':
network_ChannelJoin( 4 );
break;
case '5':
network_ChannelJoin( 5 );
break;
case '6':
network_ChannelJoin( 6 );
break;
case '7':
network_ChannelJoin( 7 );
break;
case '8':
network_ChannelJoin( 8 );
break;
case '9':
network_ChannelJoin( 9 );
break;
default:
if( intf_ProcessKey( p_main->p_intf,
(char )msg.wParam ) )
{
intf_DbgMsg( "unhandled key '%c' (%i)",
(char)msg.wParam, msg.wParam );
}
break;
}
default:
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else return( 1 );
}
/*
* Fullscreen change
*/
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
{
p_vout->b_fullscreen = ! p_vout->b_fullscreen;
/* We need to switch between Maximized and Normal sized window */
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
if( p_vout->b_fullscreen )
{
/* Maximized window */
window_placement.showCmd = SW_SHOWMAXIMIZED;
/* Change window style, no borders and no title bar */
SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 );
}
else
{
/* Normal window */
window_placement.showCmd = SW_SHOWNORMAL;
/* Change window style, borders and title bar */
SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
}
SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
/*WinDXUpdateOverlay( p_vout );*/
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
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.
*****************************************************************************/
static void vout_SetPalette( p_vout_thread_t p_vout, u16 *red, u16 *green,
u16 *blue, u16 *transp)
{
intf_WarnMsg( 3, "vout: WinDX vout_SetPalette" );
/* Nothing yet */
}
/*****************************************************************************
* 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.
*****************************************************************************/
static void vout_Display( vout_thread_t *p_vout )
{
DDSURFACEDESC ddsd;
HRESULT dxresult;
int i;
int i_image_width = p_vout->p_rendered_pic->i_width;
int i_image_height = p_vout->p_rendered_pic->i_height;
intf_WarnMsg( 4, "vout: WinDX vout_Display" );
if( (p_vout->p_sys->p_display == NULL) )
{
intf_WarnMsg( 3, "vout: WinDX no display!!" );
return;
}
/* The first time this function is called it enables the display */
p_vout->p_sys->b_display_enabled = 1;
if( p_vout->b_need_render )
{
/* Nothing yet */
}
else
{
/*
* 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 the size of the decoded pictures has changed then we close the
* YUVOverlay (which doesn't have the right size anymore). */
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: WinDX overlay size changed" );
p_vout->p_sys->i_image_width = i_image_width;
p_vout->p_sys->i_image_height = i_image_height;
WinDXCloseYUVOverlay( p_vout );
}
if( p_vout->p_sys->p_overlay == NULL )
{
intf_WarnMsg( 3, "vout: WinDX no overlay, open one..." );
if( WinDXCreateYUVOverlay( p_vout ) )
{
intf_WarnMsg( 3, "vout: WinDX cannot open a new overlay !!" );
return;
}
/* Display the Overlay */
p_vout->p_sys->b_display_enabled = 1;
WinDXUpdateOverlay( p_vout );
}
/* Lock the overlay surface */
memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
ddsd.dwSize = sizeof(DDSURFACEDESC);
dxresult = IDirectDrawSurface_Lock(p_vout->p_sys->p_overlay, NULL,
&ddsd, DDLOCK_NOSYSLOCK, NULL);
if ( dxresult == DDERR_SURFACELOST )
{
/* Your surface can be lost (thanks to windows) so be sure
* to check this and restore it if needed */
dxresult = IDirectDrawSurface_Restore( p_vout->p_sys->p_overlay );
dxresult = IDirectDrawSurface_Lock( p_vout->p_sys->p_overlay,
NULL, &ddsd, DDLOCK_NOSYSLOCK
| DDLOCK_WAIT, NULL);
}
if( dxresult != DD_OK )
{
intf_WarnMsg( 3, "vout: WinDX could not lock the surface" );
return;
}
/* 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++)
{
/* 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);
}
/* Unlock the Surface */
dxresult = IDirectDrawSurface_Unlock(p_vout->p_sys->p_overlay,
ddsd.lpSurface );
}
}
/* following functions are local */
/*****************************************************************************
* WinDXEventProc: This is the window event processing function.
*****************************************************************************
* On Windows, when you create a window you have to attach an event processing
* function to it. The aim of this function is to manage "Queued Messages" and
* "Nonqueued Messages".
* Queued Messages are those picked up and retransmitted by vout_Manage
* (using the GetMessage function).
* Nonqueued Messages are those that Windows will send directly to this
* function (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
*****************************************************************************/
long FAR PASCAL WinDXEventProc( HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_ACTIVATEAPP:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_ACTIVEAPP" );
break;
case WM_SETCURSOR:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_SETCURSOR" );
/* turn the cursor off by setting it's value to NULL */
SetCursor(NULL);
break;
case WM_CREATE:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_CREATE" );
break;
/* test your key states in this case */
case WM_KEYDOWN:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_KEYDOWN" );
switch( wParam )
{
case VK_ESCAPE:
case VK_F12:
PostMessage(hwnd,WM_CLOSE,0,0);
break;
}
break;
/* this case is touched when the application is shutting down */
case WM_DESTROY:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_DESTROY" );
PostQuitMessage( 0 );
break;
case WM_QUIT:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_QUIT" );
break;
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_SCREENSAVE: /* catch the screensaver */
case SC_MONITORPOWER: /* catch the monitor turn-off */
intf_WarnMsg( 3, "vout: WinDX WinProc WM_SYSCOMMAND" );
return 0; /* this stops them from happening */
}
break;
case WM_MOVE:
case WM_SIZE:
case WM_WINDOWPOSCHANGED:
intf_WarnMsg( 3, "vout: WinDX WinProc WM_MOVE, WMSIZE" );
PostMessage(hwnd,WM_MOVE,0,0);
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
/*****************************************************************************
* WinDXCreateWindow: create a windows window where the video will play.
*****************************************************************************
* Before creating a direct draw surface, we need to create a window in which
* the video will be displayed. This window will also allow us to capture the
* events.
*****************************************************************************/
static int WinDXCreateWindow( vout_thread_t *p_vout )
{
HINSTANCE hInstance;
WNDCLASS wc; /* window class components */
RECT rect_window;
intf_WarnMsg( 3, "vout: WinDX WinDXCreateWindow" );
/* get this module's instance */
hInstance = GetModuleHandle(NULL);
/* fill in the window class structure */
wc.style = 0; /* no special styles */
wc.lpfnWndProc = (WNDPROC)WinDXEventProc; /* event handler */
wc.cbClsExtra = 0; /* no extra class data */
wc.cbWndExtra = 0; /* no extra window data */
wc.hInstance = hInstance; /* instance */
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); /* load a default icon */
wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
wc.hbrBackground = NULL; /* redraw our own bg */
wc.lpszMenuName = NULL; /* no menu */
wc.lpszClassName = "VLC DirectX"; /* use a special class */
/* register the window class */
if (!RegisterClass(&wc)) {
intf_WarnMsg( 3, "vout: WinDX register window FAILED" );
return (1);
}
/* when you create a window you give the dimensions you wish it to have.
* Unfortunatly these dimensions will include the borders and title bar.
* We use the following function to find out the size of the window
* corresponding to the useable surface we want */
rect_window.top = 10;
rect_window.left = 10;
rect_window.right = rect_window.left + p_vout->p_sys->i_window_width;
rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
/* create the window */
p_vout->p_sys->hwnd = CreateWindow("VLC DirectX",/* name of window class */
"VLC DirectX", /* window title bar text */
WS_OVERLAPPEDWINDOW
| WS_SIZEBOX | WS_VISIBLE, /* window style */
10, /* default X coordinate */
10, /* default Y coordinate */
rect_window.right - rect_window.left, /* window width */
rect_window.bottom - rect_window.top, /* window height */
NULL, /* no parent window */
NULL, /* no menu in this window */
hInstance, /* handle of this program instance */
NULL); /* no additional arguments */
if (p_vout->p_sys->hwnd == NULL) {
intf_WarnMsg( 3, "vout: WinDX create window FAILED" );
return (1);
}
/* now display the window */
ShowWindow(p_vout->p_sys->hwnd, SW_SHOW);
return ( 0 );
}
/*****************************************************************************
* WinDXInitDDraw: Takes care of all the DirectDraw initialisations
*****************************************************************************
* This function initialise and allocate resources for DirectDraw.
*****************************************************************************/
static int WinDXInitDDraw( vout_thread_t *p_vout )
{
HRESULT dxresult;
DWORD flags;
intf_WarnMsg( 3, "vout: WinDX WinDXInitDDraw" );
/* Initialize DirectDraw */
dxresult = DirectDrawCreate( NULL, &p_vout->p_sys->p_ddobject, NULL );
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't initialize Direct Draw" );
return( 1 );
}
/* Set DirectDraw Cooperative level, ie what control we want over Windows
display */
if( p_vout->b_fullscreen )
{
flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
}
else
{
flags = DDSCL_NORMAL;
}
dxresult = IDirectDraw_SetCooperativeLevel( p_vout->p_sys->p_ddobject,
p_vout->p_sys->hwnd, flags );
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't set direct draw cooperative level." );
IDirectDraw_Release(p_vout->p_sys->p_ddobject);
p_vout->p_sys->p_ddobject = NULL;
return( 1 );
}
return( 0 );
}
/*****************************************************************************
* WinDXCreateDisplay: create the DirectDraw display.
*****************************************************************************
* Create and initialize display according to preferences specified in the vout
* thread fields.
*****************************************************************************/
static int WinDXCreateDisplay( vout_thread_t *p_vout )
{
DDCAPS ddcaps;
HRESULT dxresult;
DDSURFACEDESC ddsd;
BOOL bHasOverlay, bHasColorKey, bCanStretch;
intf_WarnMsg( 3, "vout: WinDX WinDXCreateDisplay" );
/* Now create the primary surface. This surface is the displayed surface */
/* The following two steps are important! */
memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
dxresult = IDirectDraw_CreateSurface( p_vout->p_sys->p_ddobject,
&ddsd,
&p_vout->p_sys->p_display, NULL );
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't create direct draw primary surface." );
p_vout->p_sys->p_display = NULL;
return( 1 );
}
/* Now create a clipper for our window.
* This clipper prevents us to modify by mistake anything on the screen
* (primary surface) which doesn't belong to our window */
dxresult = IDirectDraw_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 clipper." );
IDirectDrawSurface_Release( p_vout->p_sys->p_display );
p_vout->p_sys->p_display = NULL;
return( 1 );
}
dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0,
p_vout->p_sys->hwnd);
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't attach clipper to window." );
IDirectDrawSurface_Release( p_vout->p_sys->p_display );
p_vout->p_sys->p_display = NULL;
return( 1 );
}
dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
p_vout->p_sys->p_clipper);
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't attach clipper to surface." );
IDirectDrawSurface_Release( p_vout->p_sys->p_display );
p_vout->p_sys->p_display = NULL;
return( 1 );
}
/* Probe the capabilities of the hardware */
/* This is just an indication of whever 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 = IDirectDraw_GetCaps( p_vout->p_sys->p_ddobject,
&ddcaps, NULL );
if(dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't get caps." );
bHasOverlay = FALSE;
bHasColorKey = FALSE;
bCanStretch = FALSE;
}
else
{
/* 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: WinDX Caps: overlay=%i colorkey=%i stretch=%i",
bHasOverlay, bHasColorKey, bCanStretch );
}
if( bHasOverlay && bHasColorKey && bCanStretch )
{
if( !WinDXCreateYUVOverlay( p_vout ) )
{
/* Overlay created successfully */
p_vout->b_need_render = 0;
}
}
/* Now do some initialisation for video_output */
if( p_vout->b_need_render )
{
/* 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 = IDirectDrawSurface_Lock(p_vout->p_sys->p_display,
NULL, &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 = IDirectDrawSurface_Restore( p_vout->p_sys->p_display );
dxresult = IDirectDrawSurface_Lock( p_vout->p_sys->p_display,
NULL, &ddsd, DDLOCK_NOSYSLOCK
| DDLOCK_WAIT, NULL);
}
if( dxresult != DD_OK )
{
intf_WarnMsg( 3, "vout: WinDX could not lock the surface" );
return( 1 );
}
/* Set the pointer to the surface memory */
p_vout->p_sys->p_windx_buf[ 0 ] = ddsd.lpSurface;
/* back buffer, none for now */
p_vout->p_sys->p_windx_buf[ 1 ] = ddsd.lpSurface;
/* Set thread information */
p_vout->i_width = ddsd.dwWidth;
p_vout->i_height = ddsd.dwHeight;
p_vout->i_bytes_per_line = ddsd.u1.lPitch;
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;
/* Unlock the Surface */
dxresult = IDirectDrawSurface_Unlock(p_vout->p_sys->p_display,
ddsd.lpSurface );
/* FIXME: palette in 8bpp ?? */
/* Set and initialize buffers */
vout_SetBuffers( p_vout, p_vout->p_sys->p_windx_buf[ 0 ],
p_vout->p_sys->p_windx_buf[ 1 ] );
}
else
{
/* Lock the surface */
memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
ddsd.dwSize = sizeof(DDSURFACEDESC);
dxresult = IDirectDrawSurface_Lock(p_vout->p_sys->p_overlay,
NULL, &ddsd, DDLOCK_NOSYSLOCK, NULL);
if ( dxresult == DDERR_SURFACELOST )
{
/* Your surface can be lost (thanks to windows) so be sure
* to check this every time you want to do something with
* it */
dxresult = IDirectDrawSurface_Restore(
p_vout->p_sys->p_overlay );
dxresult = IDirectDrawSurface_Lock( p_vout->p_sys->p_overlay
, NULL, &ddsd,DDLOCK_NOSYSLOCK| DDLOCK_WAIT, NULL);
}
if( dxresult != DD_OK )
{
intf_WarnMsg( 3, "vout: WinDX could not lock the surface" );
return( 1 );
}
p_vout->p_sys->p_windx_buf[ 0 ] = ddsd.lpSurface;
p_vout->p_sys->p_windx_buf[ 1 ] = ddsd.lpSurface;
/* Set thread information */
p_vout->i_width = ddsd.dwWidth;
p_vout->i_height = ddsd.dwHeight;
p_vout->i_bytes_per_line = ddsd.u1.lPitch;
/* Unlock the Surface */
dxresult = IDirectDrawSurface_Unlock(p_vout->p_sys->p_overlay,
ddsd.lpSurface );
vout_SetBuffers( p_vout, p_vout->p_sys->p_windx_buf[ 0 ],
p_vout->p_sys->p_windx_buf[ 1 ] );
}
intf_WarnMsg( 3, "vout: WinDX End WinDXCreateDisplay" );
return( 0 );
}
/*****************************************************************************
* WinDXCreateYUVOveraly: create an YUV overlay surface for the video.
*****************************************************************************
* The best method of display is with an YUV overlay because the YUV->RGB
* conversion is done in hardware.
* This function will try to create an YUV overlay.
*****************************************************************************/
static int WinDXCreateYUVOverlay( vout_thread_t *p_vout )
{
HRESULT dxresult;
DDSURFACEDESC ddsd;
intf_WarnMsg( 3, "vout: WinDX WinDXCreateYUVOverlay" );
/* Now create the overlay surface. This overlay will be displayed on
* top of the primary surface.
* A color key is used to determine whether or not the overlay will be
* displayed, ie the overlay will be displayed in place of the primary
* surface wherever the primary surface will have this color.
* This color will be painted by WinDXClipOverlay which in turn is called
* by a WM_PAINT event */
memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC('Y','V','1','2');
ddsd.ddpfPixelFormat.u1.dwYUVBitCount = 16;
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS |
DDSD_HEIGHT |
DDSD_WIDTH |
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;
dxresult = IDirectDraw_CreateSurface( p_vout->p_sys->p_ddobject,
&ddsd,
&p_vout->p_sys->p_overlay, NULL );
if( dxresult != DD_OK )
{
intf_ErrMsg( "vout error: can't create overlay surface." );
}
else
{
intf_WarnMsg( 3, "vout: WinDX YUV overlay created successfully" );
}
/* Hide the overlay for now */
IDirectDrawSurface_UpdateOverlay(p_vout->p_sys->p_overlay,
NULL,
p_vout->p_sys->p_display,
NULL,
DDOVER_HIDE,
NULL);
return ( 0 );
}
/*****************************************************************************
* WinDXUpdateOverlay: Move or resize overlay surface on video display.
*****************************************************************************
* This function is used to move or resize an overlay surface on the screen.
* Ususally the overlay is moved by the user and thus, by a move or resize
* event (in vout_Manage).
*****************************************************************************/
static int WinDXUpdateOverlay( vout_thread_t *p_vout )
{
DDOVERLAYFX ddofx;
RECT rect_window, rect_client;
DWORD dwFlags;
HRESULT dxresult;
intf_WarnMsg( 3, "vout: WinDX WinDXUpdateOverlay" );
if( p_vout->p_sys->p_overlay == NULL || p_vout->b_need_render)
{
intf_WarnMsg( 3, "vout: WinDX no overlay !!" );
return( 0 );
}
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 rect_client.right = rect_client.top = 0 */
GetWindowRect(p_vout->p_sys->hwnd, &rect_window);
GetClientRect(p_vout->p_sys->hwnd, &rect_client);;
rect_window.left = ( (rect_window.right - rect_window.left) -
rect_client.right ) / 2 + rect_window.left;
rect_window.right = rect_window.left + rect_client.right;
rect_window.top = rect_window.bottom - rect_client.bottom;
/* We want to keep the aspect ratio of the video */
if( p_vout->b_scale )
{
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
{
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);
}
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_SQUARE_PICTURE:
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);
}
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;
case AR_3_4_PICTURE:
default:
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;
}
}
/* Position and show the overlay */
memset(&ddofx, 0, sizeof(DDOVERLAYFX));
ddofx.dwSize = sizeof(DDOVERLAYFX);
ddofx.dckDestColorkey.dwColorSpaceLowValue = OVERLAY_COLOR_KEY;
ddofx.dckDestColorkey.dwColorSpaceHighValue = OVERLAY_COLOR_KEY;
dwFlags = DDOVER_KEYDESTOVERRIDE | DDOVER_SHOW;
dxresult = IDirectDrawSurface_UpdateOverlay(p_vout->p_sys->p_overlay,
NULL,
p_vout->p_sys->p_display,
&rect_window,
dwFlags,
&ddofx);
if(dxresult != DD_OK)
{
intf_WarnMsg( 3, "vout: WinDX WM_MOVE can't move or resize overlay" );
}
return ( 0 );
}
/*****************************************************************************
* WinDXClipOveraly: Clip overlay surface on video display.
*****************************************************************************
* The overlay is displayed on top of the primary surface (which is the
* screen).
* This overlay must be clipped whenever another window is supposed to cover
* it.
* For this, we use a color key which we paint on the parts of the window
* which aren't covered by anything else. The video adapter will then only
* display the overlay on the surfaces painted with this color key.
* This function is called whenever a WM_PAINT event is generated
* (in vout_Manage).
*****************************************************************************/
static int WinDXClipOverlay( vout_thread_t *p_vout )
{
PAINTSTRUCT ps;
POINT ptClient;
RECT rectBlt;
DDBLTFX ddbfx;
intf_WarnMsg( 3, "vout: WinDX WinDXClipOverlay" );
if( p_vout->p_sys->p_overlay == NULL || p_vout->b_need_render)
{
intf_WarnMsg( 3, "vout: WinDX no overlay !!" );
return( 0 );
}
BeginPaint(p_vout->p_sys->hwnd, &ps);
/* Fill the client area with colour key */
ptClient.x = ps.rcPaint.left;
ptClient.y = ps.rcPaint.top;
ClientToScreen(p_vout->p_sys->hwnd, &ptClient);
rectBlt.left = ptClient.x;
rectBlt.top = ptClient.y;
ptClient.x = ps.rcPaint.right;
ptClient.y = ps.rcPaint.bottom;
ClientToScreen(p_vout->p_sys->hwnd, &ptClient);
rectBlt.right = ptClient.x;
rectBlt.bottom = ptClient.y;
memset(&ddbfx, 0, sizeof(DDBLTFX));
ddbfx.dwSize = sizeof(DDBLTFX);
ddbfx.u5.dwFillColor = OVERLAY_COLOR_KEY;
IDirectDrawSurface_Blt(p_vout->p_sys->p_display,
&rectBlt,
NULL,
&rectBlt,
DDBLT_COLORFILL, // | DDBLT_WAIT,
&ddbfx);
EndPaint(p_vout->p_sys->hwnd, &ps);
return ( 0 );
}
/*****************************************************************************
* WinDXCloseWindow: close the window created by WinDXCreateWindow
*****************************************************************************
* This function returns all resources allocated by WinDXCreateWindow.
*****************************************************************************/
static void WinDXCloseWindow( vout_thread_t *p_vout )
{
HINSTANCE hInstance;
intf_WarnMsg( 3, "vout: WinDX vout_WinDXCloseWindow" );
if( p_vout->p_sys->hwnd != INVALID_HANDLE_VALUE )
{
DestroyWindow( p_vout->p_sys->hwnd);
p_vout->p_sys->hwnd = INVALID_HANDLE_VALUE;
}
hInstance = GetModuleHandle(NULL);
UnregisterClass( "VLC DirectX", /* class name */
hInstance ); /* handle to application instance */
}
/*****************************************************************************
* WinDXCloseDDraw: Release the DDraw object allocated by WinDXInitDDraw
*****************************************************************************
* This function returns all resources allocated by WinDXInitDDraw.
*****************************************************************************/
static void WinDXCloseDDraw( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: WinDX WinDXCloseDDraw" );
if( p_vout->p_sys->p_ddobject != NULL )
{
IDirectDraw_Release(p_vout->p_sys->p_ddobject);
p_vout->p_sys->p_ddobject = NULL;
}
}
/*****************************************************************************
* WinDXCloseDisplay: close and reset DirectX device
*****************************************************************************
* This function returns all resources allocated by WinDXCreateDisplay and
* restore the original state of the device.
*****************************************************************************/
static void WinDXCloseDisplay( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: WinDX vout_WinDXCloseDisplay" );
if( p_vout->p_sys->p_display != NULL )
{
if( p_vout->p_sys->p_overlay != NULL )
{
IDirectDraw_Release( p_vout->p_sys->p_overlay );
p_vout->p_sys->p_overlay = NULL;
}
if( p_vout->p_sys->p_clipper != NULL )
{
IDirectDraw_Release( p_vout->p_sys->p_clipper );
p_vout->p_sys->p_clipper = NULL;
}
IDirectDraw_Release( p_vout->p_sys->p_display );
p_vout->p_sys->p_display = NULL;
}
}
/*****************************************************************************
* WinDXCloseYUVOverlay: close the overlay surface
*****************************************************************************
* This function returns all resources allocated by the overlay 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).
*****************************************************************************/
static void WinDXCloseYUVOverlay( vout_thread_t *p_vout )
{
intf_WarnMsg( 3, "vout: WinDX vout_WinDXCloseYUVOverlay" );
if( p_vout->p_sys->p_overlay != NULL )
{
IDirectDraw_Release( p_vout->p_sys->p_overlay );
p_vout->p_sys->p_overlay = NULL;
}
p_vout->p_sys->b_display_enabled = 0;
}
-- Attached file included as plaintext by Listar --
/*****************************************************************************
* windx.c : Windows DirectX plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
* $Id: windx.c,v 1.00 2001/04/28 03:36:25 sam Exp $
*
* Authors: Samuel Hocevar <sam at zoy.org>
* Pierre Baillet <oct at zoy.org>
* Arnaud de Bossoreille de Ribou <bozo at via.ecp.fr>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#define MODULE_NAME windx
#include "modules_inner.h"
/*****************************************************************************
* Preamble
*****************************************************************************/
#include "defs.h"
#include <stdlib.h> /* malloc(), free() */
#include "config.h"
#include "common.h" /* boolean_t, byte_t */
#include "threads.h"
#include "mtime.h"
#include "audio_output.h"
#include "video.h"
#include "video_output.h"
#include "modules.h"
/*****************************************************************************
* Building configuration tree
*****************************************************************************/
MODULE_CONFIG_START
ADD_WINDOW( "Configuration for Windows DirectX module" )
ADD_COMMENT( "For now, the Windows DirectX module cannot be configured" )
MODULE_CONFIG_END
/*****************************************************************************
* Capabilities defined in the other files.
*****************************************************************************/
void _M( aout_getfunctions )( function_list_t * p_function_list );
void _M( vout_getfunctions )( function_list_t * p_function_list );
/*****************************************************************************
* InitModule: get the module structure and configuration.
*****************************************************************************
* We have to fill psz_name, psz_longname and psz_version. These variables
* will be strdup()ed later by the main application because the module can
* be unloaded later to save memory, and we want to be able to access this
* data even after the module has been unloaded.
*****************************************************************************/
MODULE_INIT
{
p_module->psz_name = MODULE_STRING;
p_module->psz_longname = "DirectX module";
p_module->psz_version = VERSION;
p_module->i_capabilities = MODULE_CAPABILITY_NULL
| MODULE_CAPABILITY_VOUT
| MODULE_CAPABILITY_AOUT;
return( 0 );
}
/*****************************************************************************
* ActivateModule: set the module to an usable state.
*****************************************************************************
* This function fills the capability functions and the configuration
* structure. Once ActivateModule() has been called, the i_usage can
* be set to 0 and calls to NeedModule() be made to increment it. To unload
* the module, one has to wait until i_usage == 0 and call DeactivateModule().
*****************************************************************************/
MODULE_ACTIVATE
{
p_module->p_functions = malloc( sizeof( module_functions_t ) );
if( p_module->p_functions == NULL )
{
return( -1 );
}
_M( aout_getfunctions )( &p_module->p_functions->aout );
_M( vout_getfunctions )( &p_module->p_functions->vout );
p_module->p_config = p_config;
return( 0 );
}
/*****************************************************************************
* DeactivateModule: make sure the module can be unloaded.
*****************************************************************************
* This function must only be called when i_usage == 0. If it successfully
* returns, i_usage can be set to -1 and the module unloaded. Be careful to
* lock usage_lock during the whole process.
*****************************************************************************/
MODULE_DEACTIVATE
{
free( p_module->p_functions );
return( 0 );
}
More information about the vlc-devel
mailing list