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