From e1d8559090fc00da048617282fcdde34a8b345ea Mon Sep 17 00:00:00 2001 From: Tim Champagne Date: Tue, 22 Apr 2003 20:09:38 +0000 Subject: Adding a couple of files missing files for the Win32/msvc port (audio and video directx) CVS patchset: 4648 CVS date: 2003/04/22 20:09:38 --- src/audio_out/audio_directx_out.c | 949 +++++++++++++++++++++++++++ src/video_out/video_out_directx.c | 1289 +++++++++++++++++++++++++++++++++++++ src/video_out/video_out_win32.h | 67 ++ 3 files changed, 2305 insertions(+) create mode 100755 src/audio_out/audio_directx_out.c create mode 100755 src/video_out/video_out_directx.c create mode 100755 src/video_out/video_out_win32.h diff --git a/src/audio_out/audio_directx_out.c b/src/audio_out/audio_directx_out.c new file mode 100755 index 000000000..2d233278e --- /dev/null +++ b/src/audio_out/audio_directx_out.c @@ -0,0 +1,949 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine 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. + * + * xine 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-1307, USA + * + * audio_directx_out.c, direct sound audio output plugin for xine + * by Matthew Grooms + */ + +typedef unsigned char boolean; + +#include +#include +#include "audio_out.h" +#include "xine_internal.h" + + +#if (0) +#define LOG 1 +#endif + +#define MAX_CHANNELS 6 +#define MAX_BITS 16 +#define MAX_SAMPLE_RATE 44100 +#define SOUND_BUFFER_DIV 32 +#define SOUND_BUFFER_MAX MAX_CHANNELS * MAX_BITS * MAX_SAMPLE_RATE / SOUND_BUFFER_DIV + +#define DSBUFF_INIT 0 +#define DSBUFF_LEFT 1 +#define DSBUFF_RIGHT 2 + +#define AO_DIRECTX_IFACE_VERSION 7 + +// ----------------------------------------- +// +// ao_directx driver struct +// +// ----------------------------------------- + +typedef struct ao_directx_s +{ + ao_driver_t ao_driver; + + int capabilities; + + // directx objects + + LPDIRECTSOUND dsobj; + LPDIRECTSOUNDBUFFER dsbuffer; + DSBCAPS dsbcaps; + LPDIRECTSOUNDNOTIFY notify; + DSBPOSITIONNOTIFY notify_events[ 2 ]; + + // buffer vars + + long buffer_size; + long buffer_init; + int write_status; + long write_pos; + + uint8_t prebuff[ SOUND_BUFFER_MAX ]; + uint32_t prebuff_size; + + // current buffer properties + + int bits; + int rate; + int chnn; + int frsz; + + // current mixer settings + + int mute; + int volume; + +}ao_directx_t; + +typedef struct { + audio_driver_class_t driver_class; + + config_values_t *config; + + char *device_name; +} audiox_class_t; + +// ------------------------------------------- +// +// BEGIN : Direct Sound and win32 handlers +// for xine audio output plugins. +// +// ------------------------------------------- + +boolean CreateDirectSound( ao_directx_t * ao_directx ); +void DestroyDirectSound( ao_directx_t * ao_directx ); +boolean CreateSoundBuffer( ao_directx_t * ao_directx ); +void DestroySoundBuffer( ao_directx_t * ao_directx ); +uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * samples ); + +// Display formatted error message in +// popup message box. + +void Error( HWND hwnd, LPSTR szfmt, ... ) +{ + char tempbuff[ 256 ]; + *tempbuff = 0; + wvsprintf( &tempbuff[ strlen( tempbuff ) ], szfmt, ( char * )( &szfmt + 1 ) ); + MessageBox( hwnd, tempbuff, "Error", MB_ICONERROR | MB_OK | MB_APPLMODAL | MB_SYSTEMMODAL ); +} + +// Create our direct sound object and +// set the cooperative level. + +boolean CreateDirectSound( ao_directx_t * ao_directx ) +{ + DSCAPS dscaps; + HWND hxinewnd; + +#ifdef LOG + printf("audio_directx_out: CreateDirectSound(%08x) Enter\n", (unsigned long)ao_directx); +#endif + + // create direct sound object + + if( DirectSoundCreate( 0, &ao_directx->dsobj, 0 ) != DS_OK ) + { + Error( 0, "DirectSoundCreate : Unable to create direct sound object" ); +#ifdef LOG + printf("audio_directx_out: CreateDirectSound() Exit! Returning False\n"); +#endif + return FALSE; + } + + + // try to get our current xine window + + hxinewnd = FindWindow( "xinectrlwindow", "xine" ); + if( !hxinewnd ) + hxinewnd = GetDesktopWindow(); + + // set direct sound cooperative level + + if( IDirectSound_SetCooperativeLevel( ao_directx->dsobj, hxinewnd, DSSCL_EXCLUSIVE ) != DS_OK ) + { + Error( 0, "IDirectSound_SetCooperativeLevel : could not set direct sound cooperative level" ); +#ifdef LOG + printf("audio_directx_out: CreateDirectSound() Exit! Returning False\n"); +#endif + return FALSE; + } + + // get the direct sound device caps + + memset( &dscaps, 0, sizeof( dscaps ) ); + dscaps.dwSize = sizeof( dscaps ); + if( IDirectSound_GetCaps( ao_directx->dsobj, &dscaps ) != DS_OK ) + { + Error( 0, "IDirectSound_GetCaps : Unable to get direct sound device capabilities" ); +#ifdef LOG + printf("audio_directx_out: CreateDirectSound() Exit! Returning False\n"); +#endif + return FALSE; + } + +#ifdef LOG + printf("audio_directx_out: CreateDirectSound() Exit! Returning True\n"); +#endif + return TRUE; +} + +// Destroy all direct sound allocated +// resources. + +void DestroyDirectSound( ao_directx_t * ao_directx ) +{ + +#ifdef LOG + printf("audio_directx_out: DestroyDirectSound(%08x) Enter\n", (unsigned long)ao_directx); +#endif + + if( ao_directx->dsobj ) + { +#ifdef LOG + printf("audio_directx_out: IDirectSound_Release()\n"); +#endif + + IDirectSound_Release( ao_directx->dsobj ); + ao_directx->dsobj = 0; + } + +#ifdef LOG + printf("audio_directx_out: DestroyDirectSound() Exit\n"); +#endif + +} + +// Used to create directx sound buffer, +// notification events, and initialize +// buffer to null sample data. + +boolean CreateSoundBuffer( ao_directx_t * ao_directx ) +{ + DSBUFFERDESC dsbdesc; + PCMWAVEFORMAT pcmwf; + +#ifdef LOG + printf("audio_directx_out: CreateSoundBuffer(%08x) Enter\n", (unsigned long)ao_directx); +#endif + + // calculate buffer and frame size + + ao_directx->frsz = ( ao_directx->bits / 8 ) * ao_directx->chnn; + ao_directx->buffer_size = ( ao_directx->frsz * ao_directx->rate ) / SOUND_BUFFER_DIV; + + // release any existing sound buffer + // related resources + + DestroySoundBuffer( ao_directx ); + + // create a secondary sound buffer + + memset( &pcmwf, 0, sizeof( PCMWAVEFORMAT ) ); + pcmwf.wBitsPerSample = ( unsigned short ) ao_directx->bits; + pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; + pcmwf.wf.nChannels = ao_directx->chnn; + pcmwf.wf.nSamplesPerSec = ao_directx->rate; + pcmwf.wf.nBlockAlign = ao_directx->frsz; + pcmwf.wf.nAvgBytesPerSec = ao_directx->rate * ao_directx->frsz; + + memset( &dsbdesc, 0, sizeof( DSBUFFERDESC ) ); + dsbdesc.dwSize = sizeof( DSBUFFERDESC ); + dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | + DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY; + dsbdesc.dwBufferBytes = ao_directx->buffer_size; + dsbdesc.lpwfxFormat = ( LPWAVEFORMATEX ) &pcmwf; + + if( IDirectSound_CreateSoundBuffer( ao_directx->dsobj, &dsbdesc, + &ao_directx->dsbuffer, 0 ) != DS_OK ) + { + Error( 0, "IDirectSound_CreateSoundBuffer : Unable to create secondary sound buffer" ); + return FALSE; + } + + // get the buffer capabilities + + memset( &ao_directx->dsbcaps, 0, sizeof( DSBCAPS ) ); + ao_directx->dsbcaps.dwSize = sizeof( DSBCAPS ); + + if( IDirectSound_GetCaps( ao_directx->dsbuffer, &ao_directx->dsbcaps ) != DS_OK ) + { + Error( 0, "IDirectSound_GetCaps : Unable to get secondary sound buffer capabilities" ); + return FALSE; + } + + // create left side notification ( non-signaled ) + + ao_directx->notify_events[ 0 ].hEventNotify = CreateEvent( NULL, FALSE, FALSE, NULL ); + + // create right side notification ( signaled ) + + ao_directx->notify_events[ 1 ].hEventNotify = CreateEvent( NULL, FALSE, FALSE, NULL ); + + if( !ao_directx->notify_events[ 0 ].hEventNotify || !ao_directx->notify_events[ 1 ].hEventNotify ) + { + Error( 0, "CreateEvent : Unable to create sound notification events" ); + return FALSE; + } + + // get the direct sound notification interface + + if( IDirectSoundBuffer_QueryInterface( ao_directx->dsbuffer, + &IID_IDirectSoundNotify, + (LPVOID *)&ao_directx->notify ) != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_QueryInterface : Unable to get notification interface" ); + return FALSE; + } + + // set notification events + + ao_directx->notify_events[ 0 ].dwOffset = 0; + ao_directx->notify_events[ 1 ].dwOffset = ao_directx->buffer_size / 2; + + if( IDirectSoundNotify_SetNotificationPositions( ao_directx->notify, 2, + ao_directx->notify_events ) != DS_OK ) + { + Error( 0, "IDirectSoundNotify_SetNotificationPositions : Unable to set notification positions" ); + return FALSE; + } + + // DEBUG : set sound buffer volume + + if( IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MAX ) != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_SetVolume : Unable to set sound buffer volume" ); + return FALSE; + } + + // initialize our sound buffer + + IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MIN ); + FillSoundBuffer( ao_directx, DSBUFF_INIT, 0 ); + + return TRUE; + +#ifdef LOG + printf("audio_directx_out: CreateSoundBuffer() Exit\n"); +#endif + +} + +// Destroy all direct sound buffer allocated +// resources. + +void DestroySoundBuffer( ao_directx_t * ao_directx ) +{ +#ifdef LOG + printf("audio_directx_out: DestroySoundBuffer(%08x) Enter\n", (unsigned long)ao_directx); +#endif + + // stop our buffer and zero it out + + if( ao_directx->dsbuffer ) + { + IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MIN ); + IDirectSoundBuffer_Stop( ao_directx->dsbuffer ); + FillSoundBuffer( ao_directx, DSBUFF_INIT, 0 ); + } + + // release our notification events + + if( ao_directx->notify_events[ 0 ].hEventNotify ) + { + CloseHandle( ao_directx->notify_events[ 0 ].hEventNotify ); + ao_directx->notify_events[ 0 ].hEventNotify = 0; + } + + if( ao_directx->notify_events[ 1 ].hEventNotify ) + { + CloseHandle( ao_directx->notify_events[ 1 ].hEventNotify ); + ao_directx->notify_events[ 1 ].hEventNotify = 0; + } + + // release our buffer notification interface + + if( ao_directx->notify ) + { + IDirectSoundNotify_Release( ao_directx->notify ); + ao_directx->notify = 0; + } + + // release our direct sound buffer + + if( ao_directx->dsbuffer ) + { + IDirectSoundBuffer_Release( ao_directx->dsbuffer ); + ao_directx->dsbuffer = 0; + } + +#ifdef LOG + printf("audio_directx_out: DestroySoundBuffer() Exit\n"); +#endif + +} + +// Used to fill our looping sound buffer +// with data. + +uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * samples ) +{ + uint8_t * buff_pointer; // pointer inside circular buffer + uint32_t buff_length; // bytes locked by pointer + uint32_t half_size; // half our sound buffer size + uint32_t result; // error result + +#ifdef LOG + if ((void*)samples != (void*)0) + printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); + else + printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); +#endif + + half_size = ao_directx->buffer_size / 2; + + if( code == DSBUFF_INIT ) + { +#ifdef LOG + printf("audio_directx_out: FillSoundBuffer: DSBUFF_INIT\n"); +#endif + + // set our new status code + + ao_directx->write_status = DSBUFF_RIGHT; + + // lock our sound buffer for write access + + result = IDirectSoundBuffer_Lock( ao_directx->dsbuffer, + 0, 0, + &buff_pointer, &buff_length, + 0, 0, DSBLOCK_ENTIREBUFFER ); + if( result != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_Lock : could not lock sound buffer" ); + return 0; + } + + // clear our entire sound buffer + + memset( buff_pointer, 0, buff_length ); + + // unlock our sound buffer + + if( IDirectSoundBuffer_Unlock( ao_directx->dsbuffer, + buff_pointer, buff_length, + 0, 0 ) != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_Unlock : could not unlock sound buffer" ); + return 0; + } + + // start the buffer playing + + if( IDirectSoundBuffer_Play( ao_directx->dsbuffer, 0, 0, DSBPLAY_LOOPING ) != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_Play : could not play sound buffer" ); + return 0 ; + } + else + IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, ao_directx->volume ); + } + else if( code == DSBUFF_LEFT ) + { +#ifdef LOG + printf("audio_directx_out: FillSoundBuffer: DSBUFF_LEFT\n"); +#endif + // set our new status code + + ao_directx->write_status = DSBUFF_RIGHT; + + // lock our sound buffer for write access + + result = IDirectSoundBuffer_Lock( ao_directx->dsbuffer, + 0, half_size, + &buff_pointer, &buff_length, + 0, 0, 0 ); + if( result != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_Lock : could not lock sound buffer" ); + return 0; + } + + // write data to our sound buffer + + memcpy( buff_pointer, samples, buff_length ); + + // unlock our sound buffer + + if( IDirectSoundBuffer_Unlock( ao_directx->dsbuffer, + buff_pointer, buff_length, + 0, 0 ) != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_Unlock : could not unlock sound buffer" ); + return 0; + } + + } + else if( code == DSBUFF_RIGHT ) + { +#ifdef LOG + printf("audio_directx_out: FillSoundBuffer: DSBUFF_RIGHT\n"); +#endif + // set our new status code + + ao_directx->write_status = DSBUFF_LEFT; + + // lock our sound buffer for write access + + result = IDirectSoundBuffer_Lock( ao_directx->dsbuffer, + half_size, half_size, + &buff_pointer, &buff_length, + 0, 0, 0 ); + if( result != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_Lock : could not lock sound buffer" ); + return 0; + } + + // write data to our sound buffer + + memcpy( buff_pointer, samples, buff_length ); + + // unlock our sound buffer + + if( IDirectSoundBuffer_Unlock( ao_directx->dsbuffer, + buff_pointer, buff_length, + 0, 0 ) != DS_OK ) + { + Error( 0, "IDirectSoundBuffer_Unlock : could not unlock sound buffer" ); + return 0; + } + } + +#ifdef LOG + printf("audio_directx_out: FillSoundBuffer() Exit\n"); +#endif + + return buff_length; +} + +// ----------------------------------------- +// +// BEGIN : Xine driver audio output plugin +// handlers. +// +// ----------------------------------------- + +static int ao_directx_control(ao_driver_t *this_gen, int cmd, ...) { + + ao_directx_t * ao_directx = ( ao_directx_t * ) this_gen; + + switch (cmd) + { + + case AO_CTRL_PLAY_PAUSE: + break; + + case AO_CTRL_PLAY_RESUME: + break; + + case AO_CTRL_FLUSH_BUFFERS: + break; + } + + return 0; +} + + + +static int ao_directx_open( ao_driver_t * ao_driver, uint32_t bits, uint32_t rate, int mode ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + +#ifdef LOG + printf("audio_directx_out: ao_directx_open(%08x, %d, %d, %d) Enter\n", (unsigned long)ao_directx, bits, rate, mode); +#endif + // store input rate and bits + + ao_directx->bits = bits; + ao_directx->rate = rate; + + // store channel count + + switch( mode ) + { + case AO_CAP_MODE_MONO: + ao_directx->chnn = 1; + printf( "ao_directx : opened in AO_CAP_MODE_MONO mode\n" ); + break; + + case AO_CAP_MODE_STEREO: + ao_directx->chnn = 2; + printf( "ao_directx : opened in AO_CAP_MODE_STEREO mode\n" ); + break; + + case AO_CAP_MODE_4CHANNEL: + ao_directx->chnn = 4; + printf( "ao_directx : opened in AO_CAP_MODE_4CHANNEL mode\n" ); + break; + + case AO_CAP_MODE_5CHANNEL: + ao_directx->chnn = 5; + printf( "ao_directx : opened in AO_CAP_MODE_5CHANNEL mode\n" ); + break; + + case AO_CAP_MODE_5_1CHANNEL: + ao_directx->chnn = 6; + printf( "ao_directx : opened in AO_CAP_MODE_5_1CHANNEL mode\n" ); + break; + + case AO_CAP_MODE_A52: + case AO_CAP_MODE_AC5: + return 0; + } + + CreateSoundBuffer( ao_directx ); + +#ifdef LOG + printf("audio_directx_out: ao_directx_open() Exit! Returning ao_directx->rate=%d\n", ao_directx->rate); +#endif + + return ao_directx->rate; +} + +static int ao_directx_num_channels( ao_driver_t * ao_driver ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + return ao_directx->chnn; +} + +static int ao_directx_bytes_per_frame( ao_driver_t * ao_driver ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + return ao_directx->frsz; +} + +static int ao_directx_get_gap_tolerance( ao_driver_t * ao_driver ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + return 5000; +} + +static int ao_directx_delay( ao_driver_t * ao_driver ) +{ + DWORD current_read; + DWORD bytes_left; + DWORD frames_left; + + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + +#ifdef LOG + printf("audio_directx_out: ao_directx_delay(%08x) Enter\n", (unsigned long)ao_directx); +#endif + + IDirectSoundBuffer_GetCurrentPosition( ao_directx->dsbuffer, ¤t_read, 0 ); + + if( ao_directx->write_pos > current_read ) + bytes_left = ( ao_directx->write_pos - current_read ); + else + bytes_left = ( ao_directx->write_pos + ao_directx->buffer_size - current_read ); + + frames_left = ( ao_directx->prebuff_size + bytes_left ) / ao_directx->frsz; + +#ifdef LOG + printf("audio_directx_out: ao_directx_delay() Exit! Returning frames_left=%d\n", frames_left); +#endif + + return frames_left; +} + +static int ao_directx_write( ao_driver_t * ao_driver, int16_t * frame_buffer, uint32_t num_frames ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + + uint32_t frame_bytes; // how many bytes to lock + uint32_t wrote; // number of bytes written + uint32_t half_size; // half our sound buffer size + +#ifdef LOG + printf("audio_directx_out: ao_directx_write(%08x, %08x, %d) Enter\n", (unsigned long)ao_directx, (unsigned long)frame_buffer, num_frames); +#endif + + // zero write counter + + wrote = 0; + + // calculate how many bytes in frame_buffer + + frame_bytes = num_frames * ao_directx->frsz; + + // calculate half our buffer size + + half_size = ao_directx->buffer_size / 2; + + // fill audio prebuff + + memcpy( ao_directx->prebuff + ao_directx->prebuff_size, frame_buffer, frame_bytes ); + ao_directx->prebuff_size = ao_directx->prebuff_size + frame_bytes; + + // check to see if we have enough in prebuff to + // fill half of our sound buffer + + while( ao_directx->prebuff_size >= half_size ) + { + // write to our sound buffer + + if( ao_directx->write_status == DSBUFF_LEFT ) + { + // wait for our read pointer to reach the right half + // of our sound buffer, we only want to write to the + // left side + + WaitForSingleObject( ao_directx->notify_events[ 1 ].hEventNotify, INFINITE ); + + // fill left half of our buffer + + wrote = FillSoundBuffer( ao_directx, DSBUFF_LEFT, ao_directx->prebuff ); + } + else if( ao_directx->write_status == DSBUFF_RIGHT ) + { + // wait for our read pointer to reach the left half, + // of our sound buffer, we only want to write to the + // right side + + WaitForSingleObject( ao_directx->notify_events[ 0 ].hEventNotify, INFINITE ); + + // fill right half of our buffer + + wrote = FillSoundBuffer( ao_directx, DSBUFF_RIGHT, ao_directx->prebuff ); + } + + // calc bytes written and store position for next write + + ao_directx->write_pos = ( ao_directx->write_pos + wrote ) % ao_directx->buffer_size; + + // copy remaining contents of prebuff and recalc size + + memcpy( ao_directx->prebuff, ao_directx->prebuff + wrote, ao_directx->prebuff_size - wrote ); + ao_directx->prebuff_size = ao_directx->prebuff_size - wrote; + } + +#ifdef LOG + printf("audio_directx_out: ao_directx_write() Exit! Returning num_frmaes=%d\n", num_frames); +#endif + + return num_frames; +} + +static void ao_directx_close( ao_driver_t * ao_driver ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + +#ifdef LOG + printf("audio_directx_out: ao_directx_close(%08x) Enter\n", (unsigned long)ao_directx); +#endif + + // release any existing sound buffer + // related resources + + DestroySoundBuffer( ao_directx ); + +#ifdef LOG + printf("audio_directx_out: ao_directx_close() Exit!\n"); +#endif + +} + +static uint32_t ao_directx_get_capabilities( ao_driver_t * ao_driver ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + return AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL; +} + +static void ao_directx_exit( ao_driver_t * ao_driver ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + +#ifdef LOG + printf("audio_directx_out: ao_directx_exit(%08x) Enter\n", (unsigned long)ao_directx); +#endif + + // release any existing sound buffer + // related resources + + DestroySoundBuffer( ao_directx ); + + // release any existing direct sound + // related resources + + DestroyDirectSound( ao_directx ); + + // free our driver + + free( ao_directx ); + +#ifdef LOG + printf("audio_directx_out: ao_directx_exit() Exit!\n"); +#endif + +} + +static int ao_directx_get_property( ao_driver_t * ao_driver, int property ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + return 0; +} + +static int ao_directx_set_property( ao_driver_t * ao_driver, int property, int value ) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) ao_driver; + +#ifdef LOG + printf("audio_directx_out: ao_directx_set_property(%08x, %d, %d) Enter\n", (unsigned long)ao_directx, property, value); +#endif + + switch( property ) + { + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: +#ifdef LOG + printf("audio_directx_out: ao_directx_set_property: AO_PROP_PCM_VOL|AO_PROP_MIXER_VOL\n"); +#endif + + ao_directx->volume = value * ( DSBVOLUME_MIN / 100 / 3); + + if( !ao_directx->mute && ao_directx->dsbuffer ) + IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, ao_directx->volume ); + + printf( "ao_directx : volume set to %d - directX volume = %d\n", value, ao_directx->volume); + + return value; + + break; + + case AO_PROP_MUTE_VOL: + +#ifdef LOG + printf("audio_directx_out: ao_directx_set_property: AO_PROP_MUTE_VOL\n"); +#endif + + ao_directx->mute = value; + + if( !ao_directx->mute && ao_directx->dsbuffer ) + IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, ao_directx->volume ); + + if( ao_directx->mute && ao_directx->dsbuffer ) + IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, DSBVOLUME_MIN ); + + printf( "ao_directx : mute toggled" ); + + return value; + + break; + } + +#ifdef LOG + printf("audio_directx_out: ao_directx_set_property() Exit! Returning ~value=%d\n", ~value); +#endif + + return ~value; +} + +static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) +{ + ao_directx_t * ao_directx = ( ao_directx_t * ) malloc( sizeof( ao_directx_t ) ); + memset( ao_directx, 0, sizeof( ao_directx_t ) ); + +#ifdef LOG + printf("audio_directx_out: open_plugin(%08x, %08x) Enter\n", (unsigned long)class_gen, (unsigned long)data); + printf("audio_directx_out: open_plugin: ao_directx=%08x\n", (unsigned long)ao_directx); +#endif + + ao_directx->ao_driver.get_capabilities = ao_directx_get_capabilities; + ao_directx->ao_driver.get_property = ao_directx_get_property; + ao_directx->ao_driver.set_property = ao_directx_set_property; + ao_directx->ao_driver.open = ao_directx_open; + ao_directx->ao_driver.num_channels = ao_directx_num_channels; + ao_directx->ao_driver.bytes_per_frame = ao_directx_bytes_per_frame; + ao_directx->ao_driver.delay = ao_directx_delay; + ao_directx->ao_driver.write = ao_directx_write; + ao_directx->ao_driver.close = ao_directx_close; + ao_directx->ao_driver.exit = ao_directx_exit; + ao_directx->ao_driver.get_gap_tolerance = ao_directx_get_gap_tolerance; + ao_directx->ao_driver.control = ao_directx_control; + + CreateDirectSound( ao_directx ); + +#ifdef LOG + printf("audio_directx_out: open_plugin() Exit! Returning ao_directx=%08x\n", (unsigned long)ao_directx); +#endif + + return ( ao_driver_t * ) ao_directx; +} + +static char* get_identifier (video_driver_class_t *this_gen) { + return "DirectX"; +} + +static char* get_description (audio_driver_class_t *this_gen) { + return _("xine audio output plugin for win32 using directx"); +} + +static void dispose_class (audio_driver_class_t *this_gen) { + + audiox_class_t *audiox = (audiox_class_t *) this_gen; + free (audiox); +} + +static void *init_class (xine_t *xine, void *data) { + + audiox_class_t *audiox; + char* device_name; + +#ifdef LOG + printf("audio_directx_out: init_class() Enter\n"); +#endif + + device_name = xine->config->register_string(xine->config, + "audio.directx_device", "/dev/audio_directx", + _("xine audio output plugin for win32 using directx"), + NULL, 10, NULL, NULL); + + /* + * from this point on, nothing should go wrong anymore + */ + audiox = (audiox_class_t *) malloc (sizeof (audiox_class_t)); + memset( audiox, 0, sizeof( audiox_class_t ) ); + + audiox->driver_class.open_plugin = open_plugin; + audiox->driver_class.get_identifier = get_identifier; + audiox->driver_class.get_description = get_description; + audiox->driver_class.dispose = dispose_class; + + audiox->config = xine->config; + audiox->device_name = device_name; + +#ifdef LOG + printf("audio_directx_out: init_class() Exit! Returning audiox=%08x\n", audiox); +#endif + + return audiox; +} + +static uint32_t audio_types[] = { + BUF_AUDIO_DIRECTX, + 0 + }; + +static decoder_info_t dec_info_audio = { + audio_types, /* supported types */ + 1 /* priority */ +}; + +/* + * exported plugin catalog entry + */ +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_OUT, AO_DIRECTX_IFACE_VERSION, "directx", XINE_VERSION_CODE, &dec_info_audio, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; + +ao_info_t *get_audio_out_plugin_info() +{ + return (ao_info_t *)&dec_info_audio; +} + diff --git a/src/video_out/video_out_directx.c b/src/video_out/video_out_directx.c new file mode 100755 index 000000000..590574da2 --- /dev/null +++ b/src/video_out/video_out_directx.c @@ -0,0 +1,1289 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine 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. + * + * xine 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-1307, USA + * + * video_out_directx.c, direct draw video output plugin for xine + * by Matthew Grooms + */ + +typedef unsigned char boolean; + +#include +#include + +#include "xine.h" +#include "video_out.h" +#include "video_out_win32.h" +#include "alphablend.h" +#include "xine_internal.h" +#include "yuv2rgb.h" + +/**/ +#define LOG 1 +/**/ + +#define NEW_YUV 1 + +/* Set to 1 for RGB support */ +#define RGB_SUPPORT 0 + +#define BORDER_SIZE 8 +#define IMGFMT_NATIVE 4 + +// ----------------------------------------- +// +// vo_directx frame struct +// +// ----------------------------------------- + +typedef struct win32_frame_s +{ + vo_frame_t vo_frame; + + uint8_t * buffer; + int format; + int width; + int height; + int size; + int rcode; + +}win32_frame_t; + +// ----------------------------------------- +// +// vo_directx driver struct +// +// ----------------------------------------- + +typedef struct +{ + vo_driver_t vo_driver; + win32_visual_t * win32_visual; + + LPDIRECTDRAW7 ddobj; // direct draw object + LPDIRECTDRAWSURFACE primary; // primary dd surface + LPDIRECTDRAWSURFACE secondary; // secondary dd surface + LPDIRECTDRAWCLIPPER ddclipper; // dd clipper object + uint8_t * contents; // secondary contents + win32_frame_t *current; // current frame + + int req_format; // requested frame format + int act_format; // actual frame format + int width; // frame with + int height; // frame height + double ratio; // frame ratio + + yuv2rgb_factory_t *yuv2rgb_factory; // used for format conversion + yuv2rgb_t *yuv2rgb; // used for format conversion + int mode; // rgb mode + int bytespp; // rgb bits per pixel + +}win32_driver_t; + + +typedef struct { + video_driver_class_t driver_class; + + config_values_t *config; + + char *device_name; +} directx_class_t; + +// ----------------------------------------- +// +// BEGIN : Direct Draw and win32 handlers +// for xine video output plugins. +// +// ----------------------------------------- + +// Display formatted error message in +// popup message box. + +void Error( HWND hwnd, LPSTR szfmt, ... ) +{ + char tempbuff[ 256 ]; + *tempbuff = 0; + wvsprintf( &tempbuff[ strlen( tempbuff ) ], szfmt, ( char * )( &szfmt + 1 ) ); + MessageBox( hwnd, tempbuff, "Error", MB_ICONERROR | MB_OK | MB_APPLMODAL | MB_SYSTEMMODAL ); +} + +// Update our drivers current knowledge +// of our windows video out posistion + +void UpdateRect( win32_visual_t * win32_visual ) +{ + if( win32_visual->FullScreen ) + { + SetRect( &win32_visual->WndRect, 0, 0, + GetSystemMetrics( SM_CXSCREEN ), + GetSystemMetrics( SM_CYSCREEN ) ); + } + else + { + GetClientRect( win32_visual->WndHnd, &win32_visual->WndRect ); + ClientToScreen( win32_visual->WndHnd, ( POINT * ) &win32_visual->WndRect ); + ClientToScreen( win32_visual->WndHnd, ( POINT * ) &win32_visual->WndRect + 1 ); + } +} + +// Create our direct draw object, primary +// surface and clipper object. +// +// NOTE : The primary surface is more or +// less a viewport into the parent desktop +// window and will always have a pixel format +// identical to the current display mode. + +boolean CreatePrimary( win32_driver_t * win32_driver ) +{ + LPDIRECTDRAW ddobj; + DDSURFACEDESC2 ddsd; + HRESULT result; + + // create direct draw object + + result = DirectDrawCreate( 0, &ddobj, 0 ); + if( result != DD_OK ) + { + Error( 0, "DirectDrawCreate : error %i", result ); + printf( "vo_out_directx : DirectDrawCreate : error %i\n", result ); + return 0; + } + + // set cooperative level + + result = IDirectDraw_SetCooperativeLevel( ddobj, win32_driver->win32_visual->WndHnd, DDSCL_NORMAL ); + if( result != DD_OK ) + { + Error( 0, "SetCooperativeLevel : error %i", result ); + return 0; + } + + // try to get new interface + + result = IDirectDraw_QueryInterface( ddobj, &IID_IDirectDraw7, (LPVOID *) &win32_driver->ddobj ); + if( result != DD_OK ) + { + Error( 0, "ddobj->QueryInterface : DirectX 7 or higher required" ); + return 0; + } + + // release our old interface + + IDirectDraw_Release( ddobj ); + + // create primary_surface + + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + result = IDirectDraw7_CreateSurface( win32_driver->ddobj, &ddsd, &win32_driver->primary, 0 ); + if( result != DD_OK ) + { + Error( 0, "CreateSurface ( primary ) : error %i ", result ); + return 0; + } + + // create our clipper object + + result = IDirectDraw7_CreateClipper( win32_driver->ddobj, 0, &win32_driver->ddclipper, 0 ); + if( result != DD_OK ) + { + Error( 0, "CreateClipper : error %i", result ); + return 0; + } + + // associate our clipper with our window + + result = IDirectDrawClipper_SetHWnd( win32_driver->ddclipper, 0, win32_driver->win32_visual->WndHnd ); + if( result != DD_OK ) + { + Error( 0, "ddclipper->SetHWnd : error %i", result ); + return 0; + } + + // associate our primary surface with our clipper + + result = IDirectDrawSurface7_SetClipper( win32_driver->primary, win32_driver->ddclipper ); + if( result != DD_OK ) + { + Error( 0, "ddclipper->SetHWnd : error %i", result ); + return 0; + } + + // store our objects in our visual struct + + UpdateRect( win32_driver->win32_visual ); + + return 1; +} + +// Create our secondary ( off screen ) buffer. +// The optimal secondary buffer is a h/w +// overlay with the same pixel format as the +// xine frame type. However, since this is +// not always supported by the host h/w, +// we will fall back to creating an rgb buffer +// in video memory qith the same pixel format +// as the primary surface. At least then we +// can use h/w scaling if supported. + +boolean CreateSecondary( win32_driver_t * win32_driver, int width, int height, int format ) +{ + DDSURFACEDESC2 ddsd; + + if( format == XINE_IMGFMT_YV12 ) + printf( "vo_out_directx : switching to YV12 overlay type\n" ); + + if( format == XINE_IMGFMT_YUY2 ) + printf( "vo_out_directx : switching to YUY2 overlay type\n" ); + +#if RGB_SUPPORT + if( format == IMGFMT_RGB ) + printf( "vo_out_directx : switching to RGB overlay type\n" ); +#endif + + if( !win32_driver->ddobj ) + return FALSE; + + // store our reqested format, + // width and height + + win32_driver->req_format = format; + win32_driver->width = width; + win32_driver->height = height; + + // if we already have a secondary + // surface then release it + + if( win32_driver->secondary ) + IDirectDrawSurface7_Release( win32_driver->secondary ); + + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwWidth = width; + ddsd.dwHeight = height; + + if( format == XINE_IMGFMT_YV12 ) + { + // the requested format is XINE_IMGFMT_YV12 + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OVERLAY; + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC; + ddsd.ddpfPixelFormat.dwYUVBitCount = 16; + ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC( 'Y', 'V', '1', '2' ); + +#ifdef LOG + printf("CreateSecondary() - act_format = (YV12) %d\n", XINE_IMGFMT_YV12); +#endif + + win32_driver->act_format = XINE_IMGFMT_YV12; + } + + if( format == XINE_IMGFMT_YUY2 ) + { + // the requested format is XINE_IMGFMT_YUY2 + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OVERLAY; + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC; + ddsd.ddpfPixelFormat.dwYUVBitCount = 16; + ddsd.ddpfPixelFormat.dwFourCC = mmioFOURCC( 'Y', 'U', 'Y', '2' ); + +#ifdef LOG + printf("CreateSecondary() - act_format = (YUY2) %d\n", XINE_IMGFMT_YUY2); +#endif + + win32_driver->act_format = XINE_IMGFMT_YUY2; + } + +#if RGB_SUPPORT + if( format == IMGFMT_RGB ) + { + // the requested format is IMGFMT_RGB + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OVERLAY; + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwYUVBitCount = 24; + ddsd.ddpfPixelFormat.dwRBitMask = 0xff0000; + ddsd.ddpfPixelFormat.dwGBitMask = 0x00ff00; + ddsd.ddpfPixelFormat.dwBBitMask = 0x0000ff; + +#ifdef LOG + printf("CreateSecondary() - act_format = (RGB) %d\n", IMGFMT_RGB); +#endif + + win32_driver->act_format = IMGFMT_RGB; + } +#endif /* RGB_SUPPORT */ + +#ifdef LOG + printf("CreateSecondary() - IDirectDraw7_CreateSurface()\n"); +#endif + + if( IDirectDraw7_CreateSurface( win32_driver->ddobj, &ddsd, &win32_driver->secondary, 0 ) == DD_OK ) + return TRUE; + + // Our fallback method is to create a back buffer + // with the same image format as the primary surface + +#ifdef LOG + printf("CreateSecondary() - Falling back to back buffer same as primary\n"); +#endif + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + +#ifdef LOG + printf("CreateSecondary() - act_format = (NATIVE) %d\n", IMGFMT_NATIVE); +#endif + + win32_driver->act_format = IMGFMT_NATIVE; + + if( IDirectDraw7_CreateSurface( win32_driver->ddobj, &ddsd, &win32_driver->secondary, 0 ) == DD_OK ) + return TRUE; + + // This is bad. We cant even create a surface with + // the same format as the primary surface. + + Error( 0, "CreateSurface ( Secondary ) : unable to create a suitable rendering surface" ); + + return FALSE; +} + +// Destroy all direct draw driver allocated +// resources. + +void Destroy( win32_driver_t * win32_driver ) +{ + if( win32_driver->ddclipper ) + IDirectDrawClipper_Release( win32_driver->ddclipper ); + + if( win32_driver->primary ) + IDirectDrawSurface7_Release( win32_driver->primary ); + + if( win32_driver->secondary ) + IDirectDrawSurface7_Release( win32_driver->secondary ); + + if( win32_driver->ddobj ) + IDirectDraw_Release( win32_driver->ddobj ); + + free( win32_driver ); +} + +// Check the current pixel format of the +// display mode. This is neccesary in case +// the h/w does not support an overlay for +// the native frame format. + +boolean CheckPixelFormat( win32_driver_t * win32_driver ) +{ + DDPIXELFORMAT ddpf; + HRESULT result; + + // get the pixel format of our primary surface + + memset( &ddpf, 0, sizeof( DDPIXELFORMAT )); + ddpf.dwSize = sizeof( DDPIXELFORMAT ); + result = IDirectDrawSurface7_GetPixelFormat( win32_driver->primary, &ddpf ); + if( result != DD_OK ) + { + Error( 0, "IDirectDrawSurface7_GetPixelFormat ( CheckPixelFormat ) : error %u", result ); + return 0; + } + + // TODO : support paletized video modes + + if( ( ddpf.dwFlags & DDPF_PALETTEINDEXED1 ) || + ( ddpf.dwFlags & DDPF_PALETTEINDEXED2 ) || + ( ddpf.dwFlags & DDPF_PALETTEINDEXED4 ) || + ( ddpf.dwFlags & DDPF_PALETTEINDEXED8 ) || + ( ddpf.dwFlags & DDPF_PALETTEINDEXEDTO8 ) ) + return FALSE; + + // store bytes per pixel + + win32_driver->bytespp = ddpf.dwRGBBitCount / 8; + + // find the rgb mode for software + // colorspace conversion + + if( ddpf.dwRGBBitCount == 32 ) + { + if( ddpf.dwRBitMask == 0xff0000 ) + win32_driver->mode = MODE_32_RGB; + else + win32_driver->mode = MODE_32_BGR; + } + + if( ddpf.dwRGBBitCount == 24 ) + { + if( ddpf.dwRBitMask == 0xff0000 ) + win32_driver->mode = MODE_24_RGB; + else + win32_driver->mode = MODE_24_BGR; + } + + if( ddpf.dwRGBBitCount == 16 ) + { + if( ddpf.dwRBitMask == 0xf800 ) + win32_driver->mode = MODE_16_RGB; + else + win32_driver->mode = MODE_16_BGR; + } + + if( ddpf.dwRGBBitCount == 15 ) + { + if( ddpf.dwRBitMask == 0x7C00 ) + win32_driver->mode = MODE_15_RGB; + else + win32_driver->mode = MODE_15_BGR; + } + + return TRUE; +} + +// Create a Direct draw surface from +// a bitmap resource.. +// +// NOTE : This is not really useful +// anymore since the xine logo code is +// being pushed to the backend. + + +LPDIRECTDRAWSURFACE7 CreateBMP( win32_driver_t * win32_driver, int resource ) +{ + LPDIRECTDRAWSURFACE7 bmp_surf; + DDSURFACEDESC2 bmp_ddsd; + HBITMAP bmp_hndl; + BITMAP bmp_head; + HDC hdc_dds; + HDC hdc_mem; + + // load our bitmap from a resource + + if( !( bmp_hndl = LoadBitmap( win32_driver->win32_visual->HInst, MAKEINTRESOURCE( resource ) ) ) ) + { + Error( 0, "CreateBitmap : could not load bmp resource" ); + return 0; + } + + // create an off screen surface with + // the same dimentions as our bitmap + + GetObject( bmp_hndl, sizeof( bmp_head ), &bmp_head ); + + memset( &bmp_ddsd, 0, sizeof( bmp_ddsd ) ); + bmp_ddsd.dwSize = sizeof( bmp_ddsd ); + bmp_ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + bmp_ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + bmp_ddsd.dwWidth = bmp_head.bmWidth; + bmp_ddsd.dwHeight = bmp_head.bmHeight; + + if( IDirectDraw7_CreateSurface( win32_driver->ddobj, &bmp_ddsd, &bmp_surf, 0 ) != DD_OK ) + { + Error( 0, "CreateSurface ( bitmap ) : could not create dd surface" ); + return 0; + } + + // get a handle to our surface dc, + // create a compat dc and load + // our bitmap into the compat dc + + IDirectDrawSurface7_GetDC( bmp_surf, &hdc_dds ); + hdc_mem = CreateCompatibleDC( hdc_dds ); + SelectObject( hdc_mem, bmp_hndl ); + + // copy our bmp from the compat dc + // into our dd surface + + BitBlt( hdc_dds, 0, 0, bmp_head.bmWidth, bmp_head.bmHeight, + hdc_mem, 0, 0, SRCCOPY ); + + // clean up + + DeleteDC( hdc_mem ); + DeleteObject( bmp_hndl ); + IDirectDrawSurface7_ReleaseDC( bmp_surf, hdc_dds ); + + return bmp_surf; +} + +// Merge overlay with the current primary +// surface. This funtion is only used when +// a h/w overlay of the current frame type +// is supported. + +boolean Overlay( LPDIRECTDRAWSURFACE7 src_surface, RECT * src_rect, + LPDIRECTDRAWSURFACE7 dst_surface, RECT * dst_rect, + COLORREF color_key ) +{ + DWORD dw_color_key; + DDPIXELFORMAT ddpf; + DDOVERLAYFX ddofx; + int flags; + HRESULT result; + + // compute the colorkey pixel value from the RGB value we've got/ + // NOTE : based on videolan colorkey code + + memset( &ddpf, 0, sizeof( DDPIXELFORMAT )); + ddpf.dwSize = sizeof( DDPIXELFORMAT ); + result = IDirectDrawSurface7_GetPixelFormat( dst_surface, &ddpf ); + if( result != DD_OK ) + { + Error( 0, "IDirectDrawSurface7_GetPixelFormat : could not get surface pixel format" ); + return FALSE; + } + + dw_color_key = ( DWORD ) color_key; + dw_color_key = ( DWORD ) ( ( ( dw_color_key * ddpf.dwRBitMask ) / 255 ) & ddpf.dwRBitMask ); + + memset( &ddofx, 0, sizeof( DDOVERLAYFX ) ); + ddofx.dwSize = sizeof( DDOVERLAYFX ); + ddofx.dckDestColorkey.dwColorSpaceLowValue = dw_color_key; + ddofx.dckDestColorkey.dwColorSpaceHighValue = dw_color_key; + + // set our overlay flags + + flags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE; + + // attempt to overlay the surface + + result = IDirectDrawSurface7_UpdateOverlay( src_surface, src_rect, dst_surface, dst_rect, flags, &ddofx ); + if( result != DD_OK ) + { + if( result == DDERR_SURFACELOST ) + { + IDirectDrawSurface7_Restore( src_surface ); + IDirectDrawSurface7_Restore( dst_surface ); + + IDirectDrawSurface7_UpdateOverlay( src_surface, src_rect, dst_surface, dst_rect, flags, &ddofx ); + } + else + { + Error( 0, "IDirectDrawSurface7_UpdateOverlay : error %i", result ); + return FALSE; + } + } + + return TRUE; +} + +// Copy our off screen surface into our primary +// surface. This funtion is only used when a +// h/w overlay of the current frame format is +// not supported. + +boolean BltCopy( LPDIRECTDRAWSURFACE7 src_surface, RECT * src_rect, + LPDIRECTDRAWSURFACE7 dst_surface, RECT * dst_rect ) +{ + DDSURFACEDESC ddsd_target; + HRESULT result; + + memset( &ddsd_target, 0, sizeof( ddsd_target ) ); + ddsd_target.dwSize = sizeof( ddsd_target ); + + // attempt to blt the surface sontents + + result = IDirectDrawSurface7_Blt( dst_surface, dst_rect, src_surface, src_rect, DDBLT_WAIT, 0 ); + if( result != DD_OK ) + { + if( result != DDERR_SURFACELOST ) + { + IDirectDrawSurface7_Restore( src_surface ); + IDirectDrawSurface7_Restore( dst_surface ); + + IDirectDrawSurface7_Blt( dst_surface, dst_rect, src_surface, src_rect, DDBLT_WAIT, 0 ); + } + else + { + Error( 0, "IDirectDrawSurface7_Blt : error %i", result ); + return FALSE; + } + } + + return TRUE; +} + +// Display our current frame. This function +// corrects frame output ratio and clipps the +// frame if nessesary. It will then handle +// moving the image contents contained in our +// secondary surface to our primary surface. + +boolean DisplayFrame( win32_driver_t * win32_driver ) +{ + int view_width; + int view_height; + int scaled_width; + int scaled_height; + int screen_width; + int screen_height; + RECT clipped; + RECT centered; + + // aspect ratio calculations + + // TODO : account for screen ratio as well + + view_width = win32_driver->win32_visual->WndRect.right - win32_driver->win32_visual->WndRect.left; + view_height = win32_driver->win32_visual->WndRect.bottom - win32_driver->win32_visual->WndRect.top; + + if( view_width / win32_driver->ratio < view_height ) + { + scaled_width = view_width - BORDER_SIZE; + scaled_height = view_width / win32_driver->ratio - BORDER_SIZE; + } + else + { + scaled_width = view_height * win32_driver->ratio - BORDER_SIZE; + scaled_height = view_height - BORDER_SIZE; + } + + // center our overlay in our view frame + + centered.left = ( view_width - scaled_width ) / 2 + win32_driver->win32_visual->WndRect.left; + centered.right = centered.left + scaled_width; + centered.top = ( view_height - scaled_height ) / 2 + win32_driver->win32_visual->WndRect.top; + centered.bottom = centered.top + scaled_height; + + // clip our overlay if it is off screen + + screen_width = GetSystemMetrics( SM_CXSCREEN ); + screen_height = GetSystemMetrics( SM_CYSCREEN ); + + if( centered.left < 0 ) + { + double x_scale = ( double ) ( view_width + centered.left ) / ( double ) view_width; + clipped.left = win32_driver->width - ( int ) ( win32_driver->width * x_scale ); + centered.left = 0; + } + else + clipped.left = 0; + + if( centered.top < 0 ) + { + double y_scale = ( double ) ( view_height + centered.top ) / ( double ) view_height; + clipped.left = win32_driver->height - ( int ) ( win32_driver->height * y_scale ); + centered.left = 0; + } + else + clipped.top = 0; + + if( centered.right > screen_width ) + { + double x_scale = ( double ) ( view_width - ( centered.right - screen_width ) ) / ( double ) view_width; + clipped.right = ( int ) ( win32_driver->width * x_scale ); + centered.right = screen_width; + } + else + clipped.right = win32_driver->width; + + if( centered.bottom > screen_height ) + { + double y_scale = ( double ) ( view_height - ( centered.bottom - screen_height ) ) / ( double ) view_height; + clipped.bottom = ( int ) ( win32_driver->height * y_scale ); + centered.bottom = screen_height; + } + else + clipped.bottom = win32_driver->height; + + // if surface is entirely off screen or the + // width or height is 0 for the overlay or + // the output view area, then return without + // overlay update + + if( ( centered.left > screen_width ) || + ( centered.top > screen_height ) || + ( centered.right < 0 ) || + ( centered.bottom < 0 ) || + ( clipped.left >= clipped.right ) || + ( clipped.top >= clipped.bottom ) || + ( view_width <= 0 ) || + ( view_height <= 0 ) ) + + return 1; + + // we have a h/w supported overlay + + if( ( win32_driver->act_format == XINE_IMGFMT_YV12 ) || ( win32_driver->act_format == XINE_IMGFMT_YUY2 ) ) + return Overlay( win32_driver->secondary, &clipped, win32_driver->primary, ¢ered, win32_driver->win32_visual->ColorKey ); + + // we do not have a h/w supported overlay + + return BltCopy( win32_driver->secondary, &clipped, win32_driver->primary, ¢ered ); +} + +// Lock our back buffer to update its contents. + +void * Lock( void * surface ) +{ + LPDIRECTDRAWSURFACE7 lock_surface = ( LPDIRECTDRAWSURFACE7 ) surface; + DDSURFACEDESC2 ddsd; + HRESULT result; + + if( !surface ) + return 0; + + memset( &ddsd, 0, sizeof( ddsd ) ); + ddsd.dwSize = sizeof( ddsd ); + + result = IDirectDrawSurface7_Lock( lock_surface, 0, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, 0 ); + if( result == DDERR_SURFACELOST ) + { + IDirectDrawSurface7_Restore( lock_surface ); + result = IDirectDrawSurface7_Lock( lock_surface, 0, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, 0 ); + + if( result != DD_OK ) + return 0; + + } + else if( result != DD_OK ) + { + if( result == DDERR_GENERIC ) + { + Error( 0, "surface->Lock : error, DDERR_GENERIC" ); + exit( 1 ); + } + } + + return ddsd.lpSurface; + + return 0; +} + +// Unlock our back buffer to prepair for display. + +void Unlock( void * surface ) +{ + LPDIRECTDRAWSURFACE7 lock_surface = ( LPDIRECTDRAWSURFACE7 ) surface; + + if( !surface ) + return; + + IDirectDrawSurface7_Unlock( lock_surface, 0 ); +} + +// ----------------------------------------- +// +// BEGIN : Xine driver video output plugin +// handlers. +// +// ----------------------------------------- + +static uint32_t win32_get_capabilities( vo_driver_t * vo_driver ) +{ + uint32_t retVal; + + retVal = VO_CAP_YV12 | VO_CAP_YUY2; + +#if RGB_SUPPORT + retVal |= VO_CAP_RGB; +#endif /* RGB_SUPPORT */ + + return retVal; +} + +static void win32_frame_field( vo_frame_t * vo_frame, int which_field ) +{ + // I have no idea what this even + // does, frame interlace stuff? +} + +static void win32_free_framedata(vo_frame_t* vo_frame) +{ + + win32_frame_t * frame = ( win32_frame_t * ) vo_frame; + + if(frame->vo_frame.base[0]) { + free(frame->vo_frame.base[0]); + frame->vo_frame.base[0] = NULL; + } + + if(frame->vo_frame.base[1]) { + free(frame->vo_frame.base[1]); + frame->vo_frame.base[1] = NULL; + } + + if(frame->vo_frame.base[2]) { + free(frame->vo_frame.base[2]); + frame->vo_frame.base[2] = NULL; + } +} + +static void win32_frame_dispose( vo_frame_t * vo_frame ) +{ + win32_frame_t * win32_frame = ( win32_frame_t * ) vo_frame; + + if( win32_frame->buffer ) + free( win32_frame->buffer ); + + win32_free_framedata(vo_frame); + + free( win32_frame ); +} + +static vo_frame_t * win32_alloc_frame( vo_driver_t * vo_driver ) +{ + win32_frame_t * win32_frame; + + win32_frame = ( win32_frame_t * ) malloc( sizeof( win32_frame_t ) ); + memset( win32_frame, 0, sizeof( win32_frame_t ) ); + + win32_frame->vo_frame.copy = NULL; + win32_frame->vo_frame.field = win32_frame_field; + win32_frame->vo_frame.dispose = win32_frame_dispose; + win32_frame->format = -1; + + return ( vo_frame_t * ) win32_frame; +} + + +static void win32_update_frame_format( vo_driver_t * vo_driver, vo_frame_t * vo_frame, uint32_t width, + uint32_t height, int ratio_code, int format, int flags ) +{ + win32_driver_t * win32_driver = ( win32_driver_t * ) vo_driver; + win32_frame_t * win32_frame = ( win32_frame_t * ) vo_frame; + + /*printf("vo_out_directx : win32_update_frame_format() - width = %d, height=%d, ratio_code=%d, format=%d, flags=%d\n", width, height, ratio_code, format, flags);*/ + + if( ( win32_frame->format != format ) || + ( win32_frame->width != width ) || + ( win32_frame->height != height ) ) + { + // free our allocated memory + + win32_free_framedata((vo_frame_t *)&win32_frame->vo_frame); + + // create new render buffer + if( format == XINE_IMGFMT_YV12 ) + { + win32_frame->vo_frame.pitches[0] = 8*((width + 7) / 8); + win32_frame->vo_frame.pitches[1] = 8*((width + 15) / 16); + win32_frame->vo_frame.pitches[2] = 8*((width + 15) / 16); + + win32_frame->vo_frame.base[0] = malloc(win32_frame->vo_frame.pitches[0] * height); + win32_frame->vo_frame.base[1] = malloc(win32_frame->vo_frame.pitches[1] * ((height+1)/2)); + win32_frame->vo_frame.base[2] = malloc(win32_frame->vo_frame.pitches[2] * ((height+1)/2)); + + win32_frame->size = win32_frame->vo_frame.pitches[0] * height * 2; + } + else if( format == XINE_IMGFMT_YUY2 ) + { + win32_frame->vo_frame.pitches[0] = 8*((width + 3) / 4); + + win32_frame->vo_frame.base[0] = malloc(win32_frame->vo_frame.pitches[0] * height * 2); + win32_frame->vo_frame.base[1] = NULL; + win32_frame->vo_frame.base[2] = NULL; + + win32_frame->size = win32_frame->vo_frame.pitches[0] * height * 2; + } +#if RGB_SUPPORT + else if( format == IMGFMT_RGB ) + { + win32_frame->size = width * height * 3; + win32_frame->buffer = malloc( win32_frame->size ); + vo_frame->base[0] = win32_frame->buffer; + } +#endif + else + { + printf ( "vo_out_directx : !!! unsupported image format %04x !!!\n", format ); + exit (1); + } + + win32_frame->format = format; + win32_frame->width = width; + win32_frame->height = height; + win32_frame->rcode = ratio_code; + } +} + +static void win32_display_frame( vo_driver_t * vo_driver, vo_frame_t * vo_frame ) +{ + win32_driver_t * win32_driver = ( win32_driver_t * ) vo_driver; + win32_frame_t * win32_frame = ( win32_frame_t * ) vo_frame; + int offset; + int size; + + // if the required width, height or format has changed + // then recreate the secondary buffer + + if( ( win32_driver->req_format != win32_frame->format ) || + ( win32_driver->width != win32_frame->width ) || + ( win32_driver->height != win32_frame->height ) ) + { + CreateSecondary( win32_driver, win32_frame->width, win32_frame->height, win32_frame->format ); + } + + // determine desired ratio + + switch( win32_frame->rcode ) + { + case ASPECT_ANAMORPHIC: + win32_driver->ratio = 16.0 / 9.0; + break; + + case ASPECT_DVB: + win32_driver->ratio = 2.0 / 1.0; + break; + + case ASPECT_SQUARE: + win32_driver->ratio = win32_frame->width / win32_frame->height; + break; + + case ASPECT_FULL: + default: + win32_driver->ratio = 4.0 / 3.0; + } + + // lock our surface to update its contents + + win32_driver->contents = Lock( win32_driver->secondary ); + + // surface unavailable, skip frame render + + if( !win32_driver->contents ) + { + vo_frame->displayed( vo_frame ); + return; + } + + // if our actual frame format is the native screen + // pixel format, we need to convert it + + if( win32_driver->act_format == IMGFMT_NATIVE ) + { + // use the software color conversion functions + // to rebuild the frame in our native screen + // pixel format ... this is slow + + if( win32_driver->req_format == XINE_IMGFMT_YV12 ) + { + // convert from yv12 to native + // screen pixel format + +#if NEW_YUV + win32_driver->yuv2rgb->configure( win32_driver->yuv2rgb, + win32_driver->width, win32_driver->height, + win32_driver->width, win32_driver->width/2, + win32_driver->width, win32_driver->height, + win32_driver->width * win32_driver->bytespp ); +#else + yuv2rgb_setup( win32_driver->yuv2rgb, + win32_driver->width, win32_driver->height, + win32_driver->width, win32_driver->width/2, + win32_driver->width, win32_driver->height, + win32_driver->width * win32_driver->bytespp ); + +#endif + + win32_driver->yuv2rgb->yuv2rgb_fun( win32_driver->yuv2rgb, + win32_driver->contents, + win32_frame->vo_frame.base[0], + win32_frame->vo_frame.base[1], + win32_frame->vo_frame.base[2] ); + } + + if( win32_driver->req_format == XINE_IMGFMT_YUY2 ) + { + // convert from yuy2 to native + // screen pixel format +#if NEW_YUV + win32_driver->yuv2rgb->configure( win32_driver->yuv2rgb, + win32_driver->width, win32_driver->height, + win32_driver->width, win32_driver->width/2, + win32_driver->width, win32_driver->height, + win32_driver->width * win32_driver->bytespp ); +#else + + yuv2rgb_setup( win32_driver->yuv2rgb, + win32_driver->width, win32_driver->height, + win32_driver->width, win32_driver->width/2, + win32_driver->width, win32_driver->height, + win32_driver->width * win32_driver->bytespp ); + +#endif + win32_driver->yuv2rgb->yuy22rgb_fun( win32_driver->yuv2rgb, + win32_driver->contents, + win32_frame->vo_frame.base[0] ); + } + +#if RGB_SUPPORT + if( win32_driver->req_format == IMGFMT_RGB ) + { + // convert from 24 bit rgb to native + // screen pixel format + + // TODO : rgb2rgb conversion + } +#endif + } + else + { + // the actual format is identical to our + // stream format. we just need to copy it + + switch(win32_frame->format) + { + case XINE_IMGFMT_YV12: + { + vo_frame_t *frame; + uint8_t *img; + + frame = vo_frame; + img = (uint8_t *)win32_driver->contents; + + offset = 0; + size = frame->pitches[0] * frame->height; + memcpy( img+offset, frame->base[0], size); + + offset += size; + size = frame->pitches[2]* frame->height / 2; + memcpy( img+offset, frame->base[2], size); + + offset += size; + size = frame->pitches[1] * frame->height / 2; + memcpy( img+offset, frame->base[1], size); + } + break; + case XINE_IMGFMT_YUY2: + memcpy( win32_driver->contents, win32_frame->vo_frame.base[0], win32_frame->vo_frame.pitches[0] * win32_frame->vo_frame.height * 2); + break; + default: + memcpy( win32_driver->contents, win32_frame->vo_frame.base[0], win32_frame->vo_frame.pitches[0] * win32_frame->vo_frame.height * 2); + break; + } + } + + // unlock the surface + + Unlock( win32_driver->secondary ); + + // scale, clip and display our frame + + DisplayFrame( win32_driver ); + + // tag our frame as displayed + if((win32_driver->current != NULL) && (win32_driver->current != vo_frame)) { + vo_frame->displayed(&win32_driver->current->vo_frame); + } + win32_driver->current = vo_frame; +} + +static void win32_overlay_blend( vo_driver_t * vo_driver, vo_frame_t * vo_frame, vo_overlay_t * vo_overlay ) +{ + win32_frame_t * win32_frame = ( win32_frame_t * ) vo_frame; + + // temporary overlay support, somthing more appropriate + // for win32 will be devised at a later date + + if( vo_overlay->rle ) + { + if( vo_frame->format == XINE_IMGFMT_YV12 ) + blend_yuv( win32_frame->vo_frame.base, vo_overlay, win32_frame->width, win32_frame->height, win32_frame->vo_frame.pitches ); + else + blend_yuy2( win32_frame->vo_frame.base[0], vo_overlay, win32_frame->width, win32_frame->height, win32_frame->vo_frame.pitches[0] ); + } +} + +static int win32_get_property( vo_driver_t * vo_driver, int property ) +{ +#ifdef LOG + printf( "win32_get_property\n" ); +#endif + + return 0; +} + +static int win32_set_property( vo_driver_t * vo_driver, int property, int value ) +{ + return value; +} + +static void win32_get_property_min_max( vo_driver_t * vo_driver, int property, int * min, int * max ) +{ + *min = 0; + *max = 0; +} + +static int win32_gui_data_exchange( vo_driver_t * vo_driver, int data_type, void * data ) +{ + win32_driver_t * win32_driver = ( win32_driver_t * ) vo_driver; + + switch( data_type ) + { + case GUI_WIN32_MOVED_OR_RESIZED: + UpdateRect( win32_driver->win32_visual ); + DisplayFrame( win32_driver ); + break; + } + + return 0; +} + + +static int win32_redraw_needed(vo_driver_t* this_gen) +{ + win32_driver_t* win32_driver = (win32_driver_t *) this_gen; + + int ret = 0; + + /* TC - May need to revisit this! */ +#ifdef TC + if( vo_scale_redraw_needed( &win32_driver->sc ) ) { + win32_gui_data_exchange(this_gen, GUI_WIN32_MOVED_OR_RESIZED, 0); + ret = 1; + } +#endif + + return ret; +} + +static void win32_exit( vo_driver_t * vo_driver ) +{ + win32_driver_t * win32_driver = ( win32_driver_t * ) vo_driver; + + free(win32_driver->win32_visual); + + Destroy( win32_driver ); +} + +static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *win32_visual) +/*vo_driver_t *init_video_out_plugin( config_values_t * config, void * win32_visual )*/ +{ + + /* Make sure that the DirectX drivers are available and present! */ + /* Not complete yet */ + + win32_driver_t * win32_driver = ( win32_driver_t * ) malloc ( sizeof( win32_driver_t ) ); + memset( win32_driver, 0, sizeof( win32_driver_t ) ); + + win32_driver->win32_visual = win32_visual; + win32_driver->vo_driver.get_capabilities = win32_get_capabilities; + win32_driver->vo_driver.alloc_frame = win32_alloc_frame ; + win32_driver->vo_driver.update_frame_format = win32_update_frame_format; + win32_driver->vo_driver.display_frame = win32_display_frame; + win32_driver->vo_driver.overlay_blend = win32_overlay_blend; + win32_driver->vo_driver.get_property = win32_get_property; + win32_driver->vo_driver.set_property = win32_set_property; + win32_driver->vo_driver.get_property_min_max = win32_get_property_min_max; + win32_driver->vo_driver.gui_data_exchange = win32_gui_data_exchange; + win32_driver->vo_driver.dispose = win32_exit; + win32_driver->vo_driver.redraw_needed = win32_redraw_needed; + + CreatePrimary( win32_driver ); + if( !CheckPixelFormat( win32_driver ) ) + { + Error( 0, "vo_directx : Your screen pixel format is not supported" ); + Destroy( win32_driver ); + return 0; + } + +#if (NEW_YUV) + win32_driver->yuv2rgb_factory = yuv2rgb_factory_init( win32_driver->mode, 0, 0 ); + win32_driver->yuv2rgb = win32_driver->yuv2rgb_factory->create_converter(win32_driver->yuv2rgb_factory); +#else + win32_driver->yuv2rgb = yuv2rgb_init( win32_driver->mode, 0, 0 ); +#endif + + return ( vo_driver_t * ) win32_driver; +} + + +static char* get_identifier (video_driver_class_t *this_gen) { + return "DirectX"; +} + +static char* get_description (video_driver_class_t *this_gen) { + return _("xine video output plugin for win32 using directx"); +} + +static void dispose_class (video_driver_class_t *this_gen) { + + directx_class_t *directx = (directx_class_t *) this_gen; + free (directx); +} + +static void *init_class (xine_t *xine, void *visual_gen) { + + directx_class_t *directx; + char* device_name; + +#ifdef TC + int fd; +#endif + + device_name = xine->config->register_string(xine->config, + "video.directx_device", "/dev/directx", + _("xine video output plugin for win32 using directx"), + NULL, 10, NULL, NULL); + +#ifdef TC + /* check for directx device */ + if((fd = open(device_name, O_RDWR)) < 0) { + printf("video_out_directx: aborting. (unable to open directx device \"%s\")\n", device_name); + return NULL; + } + close(fd); +#endif + + /* + * from this point on, nothing should go wrong anymore + */ + directx = (directx_class_t *) malloc (sizeof (directx_class_t)); + memset( directx, 0, sizeof( directx_class_t ) ); + + directx->driver_class.open_plugin = open_plugin; + directx->driver_class.get_identifier = get_identifier; + directx->driver_class.get_description = get_description; + directx->driver_class.dispose = dispose_class; + + directx->config = xine->config; + directx->device_name = device_name; + + return directx; +} + +static vo_info_t vo_info_win32 = { + 7, /* priority */ + XINE_VISUAL_TYPE_WIN32 /* visual type */ +}; + +/* + * exported plugin catalog entry + */ + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_OUT, 14, "vo_directx", XINE_VERSION_CODE, &vo_info_win32, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; + +vo_info_t * get_video_out_plugin_info() +{ + return &vo_info_win32; +} diff --git a/src/video_out/video_out_win32.h b/src/video_out/video_out_win32.h new file mode 100755 index 000000000..0cf51094e --- /dev/null +++ b/src/video_out/video_out_win32.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2000-2001 the xine project + * + * This file is part of xine, a unix video player. + * + * xine 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. + * + * xine 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-1307, USA + * + * $Id: video_out_win32.h,v 1.1 2003/04/22 20:09:39 tchamp Exp $ + * + * structs and defines specific to all win32 related output plugins + * (any win32 base xine ui should include this) + */ + +#include +#include +#include "inttypes.h" + +#include "vo_scale.h" + +#ifndef HAVE_VIDEO_OUT_WIN32_H +#define HAVE_VIDEO_OUT_WIN32_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * this is the visual data struct any win32 gui should supply + * (pass this to init_video_out_plugin or the xine_load_video_output_plugin + * utility function) + */ + +typedef struct { + + HWND WndHnd; /* handle of window associated with primary surface */ + HINSTANCE HInst; /* handle of windows application instance */ + RECT WndRect; /* rect of window client points translated to screen cooridnates */ + boolean FullScreen; /* is window fullscreen */ + HBRUSH Brush; /* window brush for background color */ + COLORREF ColorKey; /* window brush color key */ + vo_scale_t vs; + +} win32_visual_t; + +/* + * constants for gui_data_exchange's data_type parameter + */ + +#define GUI_WIN32_MOVED_OR_RESIZED 0 + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3