
Attached is the QNX RTOS module.

The audio part is the old ALSA plugin
as this is what QNX currently uses.
QSSL is moving away from ALSA though.
I just got back from vacation so I'm not
sure if this has already happened with
the release of QNX RTOS 6.1.

4 different video modes are supported:
normal memory, shared memory,
video memory, video overlay

If you have sufficient video memory available
it will be used automatically. To use video
overlay you must pass --overlay to vlc.
Shared memory must be activated manually in the src.

Known issues:
1. Using shared memory causes vlc to segfault on exit.
Haven't had time to debug this one yet.
2. Using video memory or video overlay will produce
distorted output if the window dimension leads to a
pitch not supported by the graphics card driver. 
3. Probably others that I can't think of right now :) 

DVD input:
Unencrypted DVDs work just fine. QNX currently does
not have a CAM interface, but QSSL is working on it.

The QNX RTOS port page on videolan.org needs updating. 

CSS-free DVDs not listed on the website:
Les rivieres pourpres. R2. 2000/2001?. Mathieu Kassovitz.
Dune. R2. 1984. David Lynch.

-- 
Jon Johansen
nanocrew.net


-- Attached file included as plaintext by Listar --

diff -urN vlc.cvs/Makefile.opts.in vlc/Makefile.opts.in
--- vlc.cvs/Makefile.opts.in	Wed Jul 11 04:01:03 2001
+++ vlc/Makefile.opts.in	Wed Jul 18 23:48:17 2001
@@ -74,6 +74,7 @@
 LIB_IDCTALTIVEC = @LIB_IDCTALTIVEC@
 LIB_KDE = @LIB_KDE@
 LIB_MACOSX = @LIB_MACOSX@
+LIB_QNX = @LIB_QNX@
 LIB_NCURSES = @LIB_NCURSES@
 LIB_QT = @LIB_QT@
 LIB_TS = @LIB_TS@
diff -urN vlc.cvs/configure.in vlc/configure.in
--- vlc.cvs/configure.in	Wed Jul 11 04:01:03 2001
+++ vlc/configure.in	Thu Jul 19 01:16:37 2001
@@ -413,6 +413,18 @@
    )])
 
 dnl
+dnl  QNX RTOS module
+dnl
+AC_ARG_ENABLE(qnx,
+  [  --disable-qnx           QNX RTOS support (default enabled)])
+    if test x$enable_qnx != xno; then
+      AC_CHECK_HEADERS(Ph.h, [
+        PLUGINS="${PLUGINS} qnx"
+        LIB_QNX="-lasound -lph"
+      ])
+    fi
+
+dnl
 dnl  Linux framebuffer module
 dnl
 AC_ARG_ENABLE(fb,
@@ -656,6 +668,7 @@
 AC_SUBST(LIB_IDCTALTIVEC)
 AC_SUBST(LIB_KDE)
 AC_SUBST(LIB_MACOSX)
+AC_SUBST(LIB_QNX)
 AC_SUBST(LIB_NCURSES)
 AC_SUBST(LIB_QT)
 AC_SUBST(LIB_TS)
diff -urN vlc.cvs/extras/libdvdcss/ioctl.c vlc/extras/libdvdcss/ioctl.c
--- vlc.cvs/extras/libdvdcss/ioctl.c	Mon Jun 25 13:34:08 2001
+++ vlc/extras/libdvdcss/ioctl.c	Thu Jul 19 00:22:14 2001
@@ -168,6 +168,16 @@
         *pi_copyright = p_buffer[ 4 ];
     }
 
+#elif defined( __QNXNTO__ )
+    /*
+        QNX RTOS currently doesn't have a CAM
+        interface (they're working on it though).
+        Assume DVD is not encrypted.
+    */
+
+    *pi_copyright = 0;
+    i_ret = 0;
+
 #else
     /* DVD ioctls unavailable - do as if the ioctl failed */
     i_ret = -1;
diff -urN vlc.cvs/plugins/qnx/Makefile vlc/plugins/qnx/Makefile
--- vlc.cvs/plugins/qnx/Makefile	Thu Jan  1 01:00:00 1970
+++ vlc/plugins/qnx/Makefile	Thu Jul 19 01:59:27 2001
@@ -0,0 +1,29 @@
+###############################################################################
+# vlc (VideoLAN Client) QNX RTOS module Makefile
+# (c)2001 VideoLAN
+###############################################################################
+
+#
+# Objects
+#
+
+PLUGIN_C = qnx.o aout_qnx.o vout_qnx.o
+BUILTIN_C = $(PLUGIN_C:%.o=BUILTIN_%.o)
+
+ALL_OBJ = $(PLUGIN_C) $(BUILTIN_C)
+
+#
+# Virtual targets
+#
+
+include ../../Makefile.modules
+
+#
+# Real targets
+#
+
+../../plugins/qnx.so: $(PLUGIN_C)
+	$(CC) $(PCFLAGS) -o $@ $^ $(PLCFLAGS) $(LIB_QNX) 
+
+../../plugins/qnx.a: $(BUILTIN_C)
+	ar r $@ $^
diff -urN vlc.cvs/plugins/qnx/aout_qnx.c vlc/plugins/qnx/aout_qnx.c
--- vlc.cvs/plugins/qnx/aout_qnx.c	Thu Jan  1 01:00:00 1970
+++ vlc/plugins/qnx/aout_qnx.c	Thu Jul 19 01:37:09 2001
@@ -0,0 +1,367 @@
+/*****************************************************************************
+ * aout_qnx.c : Alsa functions library
+ *****************************************************************************
+ * Copyright (C) 2000 VideoLAN
+ *
+ * Authors: Henri Fallon <henri@videolan.org>
+ * 
+ * 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 qnx 
+#include "modules_inner.h"
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#include "defs.h"
+
+#include <errno.h>                                                 /* ENOMEM */
+#include <string.h>                                            /* strerror() */
+#include <stdio.h>                                           /* "intf_msg.h" */
+#include <stdlib.h>                            /* calloc(), malloc(), free() */
+
+#include <sys/asoundlib.h>
+
+#include "config.h"
+#include "common.h"                                     /* boolean_t, byte_t */
+#include "threads.h"
+#include "mtime.h"
+#include "tests.h"
+
+#include "audio_output.h"                                   /* aout_thread_t */
+
+#include "intf_msg.h"                        /* intf_DbgMsg(), intf_ErrMsg() */
+#include "main.h"
+
+#include "modules.h"
+#include "modules_export.h"
+
+typedef struct alsa_device_s
+{
+    int i_num;
+} alsa_device_t;
+
+typedef struct alsa_card_s
+{
+    int i_num;
+} alsa_card_t;
+
+/* here we store plugin dependant informations */
+
+typedef struct aout_sys_s
+{
+    snd_pcm_t                * p_alsa_handle;
+    alsa_device_t              s_alsa_device;
+    alsa_card_t                s_alsa_card;
+    snd_pcm_channel_params_t   s_alsa_channel_params;
+    snd_pcm_format_t           s_alsa_format;
+} 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 );
+
+/*****************************************************************************
+ * 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: probes the audio device and return a score
+ *****************************************************************************
+ * This function tries to open the dps and returns a score to the plugin
+ * manager so that it can make its choice.
+ *****************************************************************************/
+static int aout_Probe( probedata_t *p_data )
+{
+    int i_open_return, i_close_return;
+    aout_sys_t local_sys;
+    /* This is the same as the beginning of the aout_Open */
+    
+    /* Initialize  */
+    local_sys.s_alsa_device.i_num = 0;
+    local_sys.s_alsa_card.i_num = 0;
+
+    /* Open device */
+    i_open_return = snd_pcm_open( &(local_sys.p_alsa_handle),
+                     local_sys.s_alsa_card.i_num,
+                     local_sys.s_alsa_device.i_num,
+                     SND_PCM_OPEN_PLAYBACK );
+    if( i_open_return )
+    {
+        intf_WarnMsg( 2, "aout info: could not probe ALSA device (%s)",
+              snd_strerror( i_open_return ) );
+        return ( 0 );
+    }
+
+    /* Close it */
+    i_close_return = snd_pcm_close( local_sys.p_alsa_handle );
+    
+    if( i_close_return )
+    {
+        intf_ErrMsg( "aout error: could not close ALSA device (%s)",
+                     snd_strerror( i_close_return ) );
+        return( 0 );
+    }
+    
+    if( TestMethod( AOUT_METHOD_VAR, "qnx" ) )
+    {
+        return( 999 );
+    }
+
+    /* And return score */
+    return( 50 );
+}    
+
+/*****************************************************************************
+ * aout_Open : creates a handle and opens an alsa device
+ *****************************************************************************
+ * This function opens an alsa device, through the alsa API
+ *****************************************************************************/
+static int aout_Open( aout_thread_t *p_aout )
+{
+    int i_open_returns;
+    
+    /* Allocate structures */
+    p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
+    if( p_aout->p_sys == NULL )
+    {
+        intf_ErrMsg( "aout error: failed allocating memory for ALSA (%s)",
+                     strerror(ENOMEM) );
+        return( 1 );
+    }
+
+    /* Initialize  */
+    p_aout->p_sys->s_alsa_device.i_num = 0;
+    p_aout->p_sys->s_alsa_card.i_num = 0;
+    /* FIXME : why not other format ? */
+    p_aout->i_format = AOUT_FMT_S16_LE;   
+    /* FIXME : why always 2 channels ?*/
+    p_aout->i_channels = 2;
+    p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR, AOUT_RATE_DEFAULT );
+    
+    /* Open device */
+    if( ( i_open_returns = snd_pcm_open( &(p_aout->p_sys->p_alsa_handle),
+                p_aout->p_sys->s_alsa_card.i_num,
+                p_aout->p_sys->s_alsa_device.i_num,
+                SND_PCM_OPEN_PLAYBACK ) ) )
+    {
+        intf_ErrMsg( "aout error: could not open ALSA device (%s)",
+             snd_strerror(i_open_returns) );
+        return( -1 );
+    }
+
+    intf_DbgMsg( "aout info: ALSA device successfully opened" );
+    return( 0 );
+}
+
+
+/*****************************************************************************
+ * aout_SetFormat : sets the alsa output format
+ *****************************************************************************
+ * This function prepares the device, sets the rate, format, the mode
+ * ("play as soon as you have data"), and buffer information.
+ *****************************************************************************/
+static int aout_SetFormat( aout_thread_t *p_aout )
+{
+    
+    int i_set_param_returns;
+    int i_prepare_playback_returns;
+    int i_playback_go_returns;
+
+    /* Fill with zeros */
+    memset( &p_aout->p_sys->s_alsa_channel_params, 0,
+            sizeof( p_aout->p_sys->s_alsa_channel_params ) );
+    
+    /* Fill the s_alsa_channel_params structure */
+
+    /* Tranfer mode and direction*/    
+    p_aout->p_sys->s_alsa_channel_params.channel = SND_PCM_CHANNEL_PLAYBACK ;
+    p_aout->p_sys->s_alsa_channel_params.mode = SND_PCM_MODE_STREAM;
+    
+    /* Format and rate */
+    p_aout->p_sys->s_alsa_channel_params.format.interleave = 1;
+    if( p_aout->i_format == AOUT_FMT_S16_LE )
+    {
+        p_aout->p_sys->s_alsa_channel_params.format.format = 
+            SND_PCM_SFMT_S16_LE;
+    }
+    else
+    {
+        p_aout->p_sys->s_alsa_channel_params.format.format = 
+            SND_PCM_SFMT_S16_BE;
+    }
+    p_aout->p_sys->s_alsa_channel_params.format.rate = p_aout->l_rate;
+    p_aout->p_sys->s_alsa_channel_params.format.voices = p_aout->i_channels ;
+    
+    /* When to start playing and when to stop */
+    p_aout->p_sys->s_alsa_channel_params.start_mode = SND_PCM_START_DATA;
+    p_aout->p_sys->s_alsa_channel_params.stop_mode = SND_PCM_STOP_STOP;
+
+    /* Buffer information . I have chosen the stream mode here
+     * instead of the block mode. I don't know whether i'm wrong 
+     * but it seemed more logical */
+    /* TODO : find the best value to put here. Probably depending
+     * on many parameters */
+    p_aout->p_sys->s_alsa_channel_params.buf.stream.queue_size = 131072; 
+    
+    p_aout->p_sys->s_alsa_channel_params.buf.stream.fill = SND_PCM_FILL_NONE ;
+    p_aout->p_sys->s_alsa_channel_params.buf.stream.max_fill = 0 ; 
+  
+    /* Now we pass this to the driver */
+    i_set_param_returns = snd_pcm_channel_params( 
+            p_aout->p_sys->p_alsa_handle, 
+            &(p_aout->p_sys->s_alsa_channel_params) );
+    
+    if( i_set_param_returns )
+    {
+        intf_ErrMsg( "aout error: unable to set parameters (%s)",
+                     snd_strerror( i_set_param_returns ) );
+        return( -1 );
+    }
+
+    /* we shall now prepare the channel */
+    i_prepare_playback_returns = 
+        snd_pcm_playback_prepare( p_aout->p_sys->p_alsa_handle );
+
+    if( i_prepare_playback_returns )
+    {
+        intf_ErrMsg( "aout error: unable to prepare channel (%s)",
+                      snd_strerror( i_set_param_returns ) );
+        return( -1 );
+    }
+    
+   /* then we may go */
+   i_playback_go_returns =
+       snd_pcm_playback_go( p_aout->p_sys->p_alsa_handle );
+    if( i_playback_go_returns )
+    {
+        intf_ErrMsg( "aout error: unable to prepare channel (bis) (%s)",
+                     snd_strerror( i_set_param_returns ) );
+        return( -1 );
+    }
+
+    p_aout->i_latency = 0;
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * aout_BufInfo: buffer status query
+ *****************************************************************************
+ * This function returns the number of used byte in the queue.
+ * It also deals with errors : indeed if the device comes to run out
+ * of data to play, it switches to the "underrun" status. It has to
+ * be flushed and re-prepared
+ *****************************************************************************/
+static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
+{
+    snd_pcm_channel_status_t alsa_channel_status;
+    int i_alsa_get_status_returns;
+    
+    memset( &alsa_channel_status, 0, sizeof( alsa_channel_status ) );
+   
+    i_alsa_get_status_returns = snd_pcm_channel_status( 
+            p_aout->p_sys->p_alsa_handle, &alsa_channel_status );
+
+    if( i_alsa_get_status_returns )
+    {
+        intf_ErrMsg( "aout error: failed getting alsa buffer info (%s)",
+                     snd_strerror ( i_alsa_get_status_returns ) );
+        return( -1 );
+    }
+
+    switch( alsa_channel_status.status )
+    {
+        case SND_PCM_STATUS_NOTREADY:
+        { 
+            intf_ErrMsg( "aout error: status NOT READY" );
+            break;
+        }
+    
+        case SND_PCM_STATUS_UNDERRUN:
+        {
+            int i_prepare_returns;
+            intf_ErrMsg( "aout error: status UNDERRUN ... resetting queue ");
+            i_prepare_returns = snd_pcm_playback_prepare( 
+                             p_aout->p_sys->p_alsa_handle );
+            if ( i_prepare_returns )
+            {
+                intf_ErrMsg( "aout error: could not flush (%s)", 
+                             snd_strerror(i_prepare_returns) );
+            }
+            break;
+        }
+    } 
+
+    return( alsa_channel_status.count );
+}
+
+/*****************************************************************************
+ * aout_Play : plays a sample
+ *****************************************************************************
+ * Plays a sample using the snd_pcm_write function from the alsa API
+ *****************************************************************************/
+static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
+{
+    int i_write_returns;
+
+    i_write_returns = (int) snd_pcm_write (
+            p_aout->p_sys->p_alsa_handle, (void *) buffer, (size_t) i_size );
+
+    if( i_write_returns <= 0 )
+    {
+        intf_ErrMsg( "aout error: writing blocks failed (%s)",
+                     snd_strerror( i_write_returns ) );
+    }
+}
+
+/*****************************************************************************
+ * aout_Close : close the Alsa device
+ *****************************************************************************/
+static void aout_Close( aout_thread_t *p_aout )
+{
+    int i_close_returns;
+
+    i_close_returns = snd_pcm_close( p_aout->p_sys->p_alsa_handle );
+
+    if( i_close_returns )
+    {
+        intf_ErrMsg( "aout error: failed closing ALSA device (%s)",
+                     snd_strerror( i_close_returns ) );
+    }
+    free( p_aout->p_sys );
+
+    intf_DbgMsg( "aout: ALSA device closed" );    
+}
+
diff -urN vlc.cvs/plugins/qnx/qnx.c vlc/plugins/qnx/qnx.c
--- vlc.cvs/plugins/qnx/qnx.c	Thu Jan  1 01:00:00 1970
+++ vlc/plugins/qnx/qnx.c	Thu Jul 19 01:27:48 2001
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ * qnx.c : QNX RTOS plugin for vlc
+ *****************************************************************************
+ * Copyright (C) 2000, 2001 VideoLAN
+ *
+ * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
+ *      
+ * 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 qnx 
+#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 "video.h"
+#include "video_output.h"
+
+#include "modules.h"
+#include "modules_export.h"
+
+/*****************************************************************************
+ * 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 );
+
+/*****************************************************************************
+ * Building configuration tree
+ *****************************************************************************/
+MODULE_CONFIG_START
+ADD_WINDOW( "Configuration for QNX RTOS module" )
+    ADD_COMMENT( "For now, the QNX RTOS module cannot be configured" )
+MODULE_CONFIG_STOP
+
+MODULE_INIT_START
+    p_module->psz_longname = "QNX RTOS module";
+    p_module->i_capabilities = MODULE_CAPABILITY_NULL
+                                | MODULE_CAPABILITY_AOUT
+                                | MODULE_CAPABILITY_VOUT;
+MODULE_INIT_STOP
+
+MODULE_ACTIVATE_START
+    _M( aout_getfunctions )( &p_module->p_functions->aout );
+    _M( vout_getfunctions )( &p_module->p_functions->vout );
+MODULE_ACTIVATE_STOP
+
+MODULE_DEACTIVATE_START
+MODULE_DEACTIVATE_STOP
diff -urN vlc.cvs/plugins/qnx/vout_qnx.c vlc/plugins/qnx/vout_qnx.c
--- vlc.cvs/plugins/qnx/vout_qnx.c	Thu Jan  1 01:00:00 1970
+++ vlc/plugins/qnx/vout_qnx.c	Thu Jul 19 01:59:35 2001
@@ -0,0 +1,845 @@
+/*****************************************************************************
+ * vout_qnx.c: QNX RTOS video output display method
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ *
+ * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
+ *
+ * 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 qnx 
+#include "modules_inner.h"
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "defs.h"
+
+#include <errno.h>                                                 /* ENOMEM */
+#include <stdlib.h>                                                /* free() */
+#include <string.h>                                            /* strerror() */
+
+#include <photon/PtWidget.h>
+#include <photon/PtWindow.h>
+#include <photon/PtLabel.h>
+#include <photon/PdDirect.h>
+
+#include "config.h"
+#include "common.h"
+#include "threads.h"
+#include "mtime.h"
+#include "tests.h"
+
+#include "video.h"
+#include "video_output.h"
+
+#include "interface.h"
+#include "intf_msg.h"
+#include "main.h"
+
+#include "modules.h"
+#include "modules_export.h"
+
+/*****************************************************************************
+ * vout_sys_t: video output QNX method descriptor
+ *****************************************************************************
+ * This structure is part of the video output thread descriptor.
+ * It describes the QNX specific properties of an output thread. QNX video
+ * output is performed through regular resizable windows. Windows can be
+ * dynamically resized to adapt to the size of the streams.
+ *****************************************************************************/
+
+#define MODE_NORMAL_MEM     0
+#define MODE_SHARED_MEM     1
+#define MODE_VIDEO_MEM      2
+#define MODE_VIDEO_OVERLAY  3
+
+typedef struct vout_sys_s
+{
+    /* video mode */
+    int                     i_mode;
+
+    /* internal stuff */
+    PtWidget_t *            p_window;
+
+    /* [shared] memory blit */
+    PhImage_t *             p_image[2];
+    int                     i_img_type;
+
+    /* video memory blit */
+    PdOffscreenContext_t *  p_ctx[2];
+    char *                  p_buf[2];
+
+    /* video overlay */
+    PgVideoChannel_t *      p_channel;
+    void *                  p_vc_y[2];
+    void *                  p_vc_u[2];
+    void *                  p_vc_v[2];
+    int                     i_vc_flags;
+    int                     i_vc_format;
+
+    /* position & dimensions */
+    PhPoint_t               pos;
+    PhDim_t                 dim;
+    PhDim_t                 old_dim;
+    PhDim_t                 screen_dim;
+} 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 int  QNXCreateWnd   ( struct vout_thread_s * );
+static int  QNXDestroyWnd  ( struct vout_thread_s * );
+static int  QNXInitDisplay ( struct vout_thread_s * );
+
+/*****************************************************************************
+ * 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 = NULL;
+}
+
+/*****************************************************************************
+ * vout_Probe: probe the video driver and return a score
+ *****************************************************************************
+ * This function tries to initialize SDL and returns a score to the
+ * plugin manager so that it can select the best plugin.
+ *****************************************************************************/
+static int vout_Probe( probedata_t *p_data )
+{
+    if( TestMethod( VOUT_METHOD_VAR, "qnx" ) )
+    {
+        return( 999 );
+    }
+
+    return( 100 );
+}
+
+/*****************************************************************************
+ * vout_Create: allocate QNX video thread output method
+ *****************************************************************************
+ * This function allocate and initialize a QNX vout method. It uses some of the
+ * vout properties to choose the window size, and change them according to the
+ * actual properties of the display.
+ *****************************************************************************/
+static int vout_Create( vout_thread_t *p_vout )
+{
+    /* init connection to photon */
+    if( PtInit( "/dev/photon" ) != 0 )
+    {
+        intf_ErrMsg( "vout error: unable to connect to photon" );
+        return( 1 );
+    }
+
+    /* allocate structure */
+    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
+    if( p_vout->p_sys == NULL )
+    {
+        intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
+        return( 1 );
+    }
+
+    memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
+
+    p_vout->b_fullscreen = 
+        main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
+    p_vout->p_sys->i_mode = 
+        main_GetIntVariable( VOUT_OVERLAY_VAR, VOUT_OVERLAY_DEFAULT ) ?
+        MODE_VIDEO_OVERLAY : MODE_NORMAL_MEM;
+    p_vout->p_sys->dim.w = 
+        main_GetIntVariable( VOUT_WIDTH_VAR, VOUT_WIDTH_DEFAULT );
+    p_vout->p_sys->dim.h = 
+        main_GetIntVariable( VOUT_HEIGHT_VAR, VOUT_HEIGHT_DEFAULT );
+    
+    /* init display and create window */
+    if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
+    {
+        free( p_vout->p_sys );
+        return( 1 );
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * vout_Init: initialize QNX video thread output method
+ *****************************************************************************
+ * This function create the buffers needed by the output thread. It is called
+ * at the beginning of the thread, but also each time the window is resized.
+ *****************************************************************************/
+static int vout_Init( vout_thread_t *p_vout )
+{
+    if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
+        p_vout->p_sys->i_mode == MODE_SHARED_MEM )
+    {
+        /* create images for [shared] memory blit */
+
+        if( !( p_vout->p_sys->p_image[0] = PhCreateImage( NULL,
+                    p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
+                    p_vout->p_sys->i_img_type, NULL, 0,
+                    p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
+            intf_ErrMsg( "vout error: cannot create image" );
+            return( 1 );
+        }
+
+        if( !( p_vout->p_sys->p_image[1] = PhCreateImage( NULL,
+                    p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
+                    p_vout->p_sys->i_img_type, NULL, 0,
+                    p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
+            intf_ErrMsg( "vout error: cannot create image" );
+            PhReleaseImage( p_vout->p_sys->p_image[0] );
+            free( p_vout->p_sys->p_image[0] );
+            p_vout->p_sys->p_image[0] = NULL;
+            return( 1 );
+        }
+        
+        /* set bytes per line, set buffers */
+        p_vout->i_bytes_per_line = p_vout->p_sys->p_image[0]->bpl;
+        p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_image[0]->image,
+                                 p_vout->p_sys->p_image[1]->image );
+    }
+    else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
+    {
+        /* create offscreen contexts for video memory blit */
+
+        if( ( p_vout->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
+                        p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
+                        Pg_OSC_MEM_PAGE_ALIGN ) ) == NULL )
+        {
+            intf_ErrMsg( "vout error: unable to create offscreen context" );
+            return( 1 );
+        }
+
+        if( ( p_vout->p_sys->p_ctx[1] = PdCreateOffscreenContext( 0,
+                        p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
+                        Pg_OSC_MEM_PAGE_ALIGN ) ) == NULL )
+        {
+            intf_ErrMsg( "vout error: unable to create offscreen context" );
+            PhDCRelease ( p_vout->p_sys->p_ctx[0] );
+            p_vout->p_sys->p_ctx[0] = NULL;
+            return( 1 );
+        }
+
+        /* get context pointers */
+        if( ( ( p_vout->p_sys->p_buf[0] =
+            PdGetOffscreenContextPtr ( p_vout->p_sys->p_ctx[0] ) ) == NULL ) ||
+            ( p_vout->p_sys->p_buf[1] =
+            PdGetOffscreenContextPtr ( p_vout->p_sys->p_ctx[1] ) ) == NULL )
+        {
+            intf_ErrMsg( "vout error: unable to get offscreen context ptr" );
+            PhDCRelease ( p_vout->p_sys->p_ctx[0] );
+            PhDCRelease ( p_vout->p_sys->p_ctx[1] );
+            p_vout->p_sys->p_ctx[0] = NULL;
+            p_vout->p_sys->p_ctx[1] = NULL;
+            return( 1 );
+        }
+
+        /* set bytes per line, clear buffers, set buffers */
+        p_vout->i_bytes_per_line = 
+            p_vout->i_bytes_per_pixel * p_vout->p_sys->dim.w;
+        memset( p_vout->p_sys->p_buf[0], 0,
+            p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
+        memset( p_vout->p_sys->p_buf[1], 0,
+            p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
+        p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_buf[0],
+                                 p_vout->p_sys->p_buf[1] );
+    }
+    else if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
+    {
+        PgScalerProps_t props;
+
+        props.size = sizeof( props );
+        props.format = p_vout->p_sys->i_vc_format; 
+        props.viewport.ul.x = p_vout->p_sys->pos.x + 4;
+        props.viewport.ul.y = p_vout->p_sys->pos.y + 20;
+        props.viewport.lr.x = p_vout->p_sys->dim.w + props.viewport.ul.x;
+        props.viewport.lr.y = p_vout->p_sys->dim.h + props.viewport.ul.y;
+        props.src_dim.w = p_vout->p_sys->dim.w;
+        props.src_dim.h    = p_vout->p_sys->dim.h;
+        props.flags = Pg_SCALER_PROP_SCALER_ENABLE |
+                      Pg_SCALER_PROP_DOUBLE_BUFFER;
+
+        if( PgConfigScalerChannel( p_vout->p_sys->p_channel, &props ) == -1 )
+        {
+            intf_ErrMsg( "vout error: unable to configure video channel" );
+            return( 1 );
+        }
+
+        p_vout->p_sys->p_vc_y[0] =
+            PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->yplane1 );
+        p_vout->p_sys->p_vc_y[1] =
+            PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->yplane2 );
+
+        if( p_vout->p_sys->p_vc_y[0] == NULL ||
+            p_vout->p_sys->p_vc_y[1] == NULL )
+        {
+            intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
+            return( 1 );
+        }
+
+        if( p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_YV12 )
+        {
+            p_vout->b_need_render = 0;
+
+            p_vout->p_sys->p_vc_u[0] =
+                PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->uplane1 );
+            p_vout->p_sys->p_vc_u[1] =
+                PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->uplane2 );
+            p_vout->p_sys->p_vc_v[0] =
+                PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->vplane1 );
+            p_vout->p_sys->p_vc_v[1] =
+                PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->vplane2 );
+
+            if( p_vout->p_sys->p_vc_u[0] == NULL ||
+                p_vout->p_sys->p_vc_u[1] == NULL ||
+                p_vout->p_sys->p_vc_v[0] == NULL ||
+                p_vout->p_sys->p_vc_v[1] == NULL )
+            {
+                intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
+                return( 1 );
+            }
+        }
+        else if( p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_RGB8888 )
+        {
+            /* set bytes per line, clear buffers, set buffers */
+            p_vout->i_bytes_per_line =
+                p_vout->i_bytes_per_pixel * p_vout->p_sys->dim.w;
+            memset( p_vout->p_sys->p_vc_y[0], 0,
+                p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
+            memset( p_vout->p_sys->p_vc_y[1], 0,
+                p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
+            p_vout->pf_setbuffers( p_vout,
+                p_vout->p_sys->p_vc_y[0], p_vout->p_sys->p_vc_y[1] );
+        }
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * vout_End: terminate QNX video thread output method
+ *****************************************************************************
+ * Destroy the buffers created by vout_Init. It is called at the end of
+ * the thread, but also each time the window is resized.
+ *****************************************************************************/
+static void vout_End( vout_thread_t *p_vout )
+{
+    if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
+        p_vout->p_sys->i_mode == MODE_SHARED_MEM ) && 
+        p_vout->p_sys->p_image[0] )
+    {
+        PhReleaseImage( p_vout->p_sys->p_image[0] );
+        PhReleaseImage( p_vout->p_sys->p_image[1] );
+        free( p_vout->p_sys->p_image[0] );
+        free( p_vout->p_sys->p_image[1] );
+    }
+    else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
+             p_vout->p_sys->p_ctx[0] )
+    {
+        PhDCRelease( p_vout->p_sys->p_ctx[0] );
+        PhDCRelease( p_vout->p_sys->p_ctx[1] );
+    }
+}
+
+/*****************************************************************************
+ * vout_Destroy: destroy QNX video thread output method
+ *****************************************************************************
+ * Terminate an output method created by vout_CreateOutputMethod
+ *****************************************************************************/
+static void vout_Destroy( vout_thread_t *p_vout )
+{
+    /* destroy the window */
+    QNXDestroyWnd( p_vout );
+
+    /* destroy structure */
+    free( p_vout->p_sys );
+}
+
+/*****************************************************************************
+ * vout_Manage: handle QNX events
+ *****************************************************************************
+ * This function should be called regularly by video output thread. It allows 
+ * window resizing. It returns a non null value on error.
+ *****************************************************************************/
+static int vout_Manage( vout_thread_t *p_vout )
+{
+    int i_ev, i_buflen;
+    PhEvent_t *p_event;
+    boolean_t b_repos = 0;
+
+    /* allocate buffer for event */
+    i_buflen = sizeof( PhEvent_t ) * 4;
+    if( ( p_event = malloc( i_buflen ) ) == NULL )
+    {
+        intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
+        return( 1 );
+    }
+
+    /* event loop */
+    do
+    {
+        memset( p_event, 0, i_buflen );
+        i_ev = PhEventPeek( p_event, i_buflen );
+
+        if( i_ev == Ph_RESIZE_MSG )
+        {
+            i_buflen = PhGetMsgSize( p_event );
+            if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
+            {
+                intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
+                return( 1 );
+            }
+        }
+        else if( i_ev == Ph_EVENT_MSG )
+        {
+            PtEventHandler( p_event );
+
+            if( p_event->type == Ph_EV_WM )
+            {
+                PhWindowEvent_t *p_ev = PhGetData( p_event );
+
+                switch( p_ev->event_f )
+                {
+                case Ph_WM_CLOSE:
+                    p_main->p_intf->b_die = 1;
+                    break;
+
+                case Ph_WM_MOVE:
+                    b_repos = 1;
+                    p_vout->p_sys->pos.x = p_ev->pos.x;
+                    p_vout->p_sys->pos.y = p_ev->pos.y;
+                    break;
+
+                case Ph_WM_RESIZE:
+                    p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
+                    p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
+                    p_vout->p_sys->dim.w = p_vout->i_width = p_ev->size.w;
+                    p_vout->p_sys->dim.h = p_vout->i_height = p_ev->size.h;
+                    p_vout->i_changes |= VOUT_SIZE_CHANGE;
+                    break;
+                }
+            }
+            else if( p_event->type == Ph_EV_KEY )
+            {
+                PhKeyEvent_t *p_ev = PhGetData( p_event );
+                long i_key = p_ev->key_sym;
+
+                if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
+                    ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
+                {
+                    switch( i_key )
+                    {
+                    case Pk_q:
+                    case Pk_Q:
+                        p_main->p_intf->b_die = 1;
+                        break;
+
+                    case Pk_f:
+                    case Pk_F:
+                        p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
+                        break;
+
+                    case Pk_c:
+                    case Pk_C:
+                        p_vout->b_grayscale = ! p_vout->b_grayscale;
+                        p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
+                        break;
+
+                    default:
+                        if( i_key >= Pk_0 && i_key <= Pk_9 )
+                        {
+                            network_ChannelJoin( i_key );
+                        }
+                        else if( intf_ProcessKey( p_main->p_intf,
+                                                    (char) i_key ) )
+                        {
+                            intf_DbgMsg( "vout: unhandled key '%c' (%i)",
+                                         (char) i_key, i_key );
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    } while( i_ev != -1 && i_ev != 0 );
+
+    free( p_event );
+
+    /*
+     * fullscreen
+     */ 
+    if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
+    {
+        PhDim_t dim;
+        PhPoint_t pos;
+
+        intf_DbgMsg( "vout: changing full-screen status" );
+
+        p_vout->b_fullscreen = !p_vout->b_fullscreen;
+        p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
+
+        if( p_vout->b_fullscreen )
+        {
+            pos.x = pos.y = 0;
+            dim.w = p_vout->p_sys->screen_dim.w + 1;
+            dim.h = p_vout->p_sys->screen_dim.h + 1;
+        }
+        else
+        {
+            pos.x = p_vout->p_sys->pos.x;
+            pos.y = p_vout->p_sys->pos.y;
+            dim.w = p_vout->p_sys->old_dim.w + 1;
+            dim.h = p_vout->p_sys->old_dim.h + 1;
+        }
+
+        PtSetResource( p_vout->p_sys->p_window,
+            Pt_ARG_WINDOW_RENDER_FLAGS,
+            p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
+            Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
+        PtSetResource( p_vout->p_sys->p_window,
+            Pt_ARG_POS, &pos, 0 );
+        PtSetResource( p_vout->p_sys->p_window,
+            Pt_ARG_DIM, &dim, 0 );
+    }
+
+    /*
+     * vout window resizing
+     */
+    if( ( p_vout->i_width  != p_vout->p_sys->dim.w ) ||
+             ( p_vout->i_height != p_vout->p_sys->dim.h ) )
+    {
+        intf_DbgMsg( "vout: resizing output window" );
+
+        p_vout->p_sys->dim.w = p_vout->i_width;
+        p_vout->p_sys->dim.h = p_vout->i_height;
+
+        /* set new dimension */
+        PtSetResource( p_vout->p_sys->p_window,
+            Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
+    }
+
+    /*
+     * size change
+     */
+    if( p_vout->i_changes & VOUT_SIZE_CHANGE )
+    {
+        intf_DbgMsg( "vout: resizing window" );
+        p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
+
+        vout_End( p_vout );
+        if( vout_Init( p_vout ) )
+        {
+            intf_ErrMsg( "vout error: cannot resize display" );
+            return( 1 );
+        }
+
+        p_vout->i_changes |= VOUT_YUV_CHANGE;
+        intf_Msg( "vout: video display resized (%dx%d)",
+                    p_vout->i_width, p_vout->i_height );
+    }
+
+    /*
+     * position change, move video channel
+     */
+    if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
+    {
+        intf_DbgMsg( "vout: moving video channel" );
+
+        vout_End( p_vout );
+        if( vout_Init( p_vout ) )
+        {
+            intf_ErrMsg( "vout error: unable to move video channel" );
+            return( 1 );
+        }
+    }
+
+    return( i_ev == -1 );
+}
+
+/*****************************************************************************
+ * vout_Display: displays previously rendered output
+ *****************************************************************************
+ * This function send the currently rendered image to QNX server, wait until
+ * it is displayed and switch the two rendering buffer, preparing next frame.
+ *****************************************************************************/
+static void vout_Display( vout_thread_t *p_vout )
+{
+    if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
+        p_vout->p_sys->i_mode == MODE_SHARED_MEM )
+    {
+        PhPoint_t pos = { 0, 0 };
+
+        PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
+        PgDrawPhImagemx( &pos, p_vout->p_sys->p_image[p_vout->i_buffer_index], 0 );
+        PgFlush();
+    }
+    else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
+    {
+        PhRect_t rc = { { 0, 0 }, { 
+                p_vout->p_sys->dim.w,
+                p_vout->p_sys->dim.h
+        } };
+
+        PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
+        PgContextBlit( p_vout->p_sys->p_ctx[p_vout->i_buffer_index], &rc, NULL, &rc );
+        PgFlush();
+    }
+    else if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY &&
+             p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_YV12 )
+    {
+        int i_size, i_index;
+
+        /* this code has NOT been tested */
+
+        i_size = p_vout->p_rendered_pic->i_width *
+                p_vout->p_rendered_pic->i_height;
+        i_index = PgNextVideoFrame( p_vout->p_sys->p_channel );
+    
+        memcpy( p_vout->p_sys->p_vc_y[i_index],
+            p_vout->p_rendered_pic->p_y, i_size );
+        memcpy( p_vout->p_sys->p_vc_v[i_index],
+            p_vout->p_rendered_pic->p_v, i_size / 4 );
+        memcpy( p_vout->p_sys->p_vc_u[i_index],
+            p_vout->p_rendered_pic->p_u, i_size / 4 );
+    }
+}
+
+/*****************************************************************************
+ * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
+ *****************************************************************************/
+static int QNXInitDisplay( p_vout_thread_t p_vout )
+{
+    PgHWCaps_t hwcaps;
+    PgDisplaySettings_t cfg;
+    PgVideoModeInfo_t minfo;
+
+    /* get graphics card hw capabilities */
+    if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
+    {
+        intf_ErrMsg( "vout error: unable to get gfx card capabilities" );
+        return( 1 );
+    }
+
+    /* get current video mode */
+    if( PgGetVideoMode( &cfg ) != 0 )
+    {
+        intf_ErrMsg( "vout error: unable to get current video mode" );
+        return( 1 );
+    }
+
+    /* get video mode info */
+    if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
+    {
+        intf_ErrMsg( "vout error: unable to get info for video mode" );
+        return( 1 );
+    }
+
+    /* use video ram if we have enough available */
+    if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
+        hwcaps.currently_available_video_ram >= 
+        ( ( minfo.width * minfo.height * minfo.bits_per_pixel ) / 8 ) )
+    {
+        intf_DbgMsg( "vout: using video ram" );
+        p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
+    }
+
+    p_vout->p_sys->i_img_type = minfo.type;
+    p_vout->p_sys->screen_dim.w = minfo.width;
+    p_vout->p_sys->screen_dim.h = minfo.height;
+    p_vout->i_screen_depth = minfo.bits_per_pixel;
+
+    switch( minfo.type )
+    {
+        case Pg_IMAGE_PALETTE_BYTE:
+            p_vout->i_bytes_per_pixel = 1;
+            break;
+
+        case Pg_IMAGE_DIRECT_555:
+        case Pg_IMAGE_DIRECT_565:
+            p_vout->i_bytes_per_pixel = 2;
+            break;
+    
+        case Pg_IMAGE_DIRECT_8888:
+            p_vout->i_bytes_per_pixel = 4;
+            break;
+    }
+
+    switch( p_vout->i_screen_depth )
+    {
+        case 15:
+            p_vout->i_red_mask   = 0x7c00;
+            p_vout->i_green_mask = 0x03e0;
+            p_vout->i_blue_mask  = 0x001f;
+            break;
+
+        case 16:
+            p_vout->i_red_mask   = 0xf800;
+            p_vout->i_green_mask = 0x07e0;
+            p_vout->i_blue_mask  = 0x001f;
+            break;
+
+        case 24:
+        case 32:
+        default:
+            p_vout->i_red_mask   = 0xff0000;
+            p_vout->i_green_mask = 0x00ff00;
+            p_vout->i_blue_mask  = 0x0000ff;
+            break;
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * QNXCreateWnd: create and realize the main window
+ *****************************************************************************/
+static int QNXCreateWnd( p_vout_thread_t p_vout )
+{
+    PtArg_t args[8];
+    PhPoint_t pos = { 0, 0 };
+    PgColor_t color = Pg_BLACK;
+
+    /* correct way to check for overlay support:
+
+        1. call PgGetGraphicsHWCaps and check
+           the results for Pg_VIDEO_OVERLAY
+        2. check if the current graphics mode
+           has PgVM_MODE_CAP1_VIDEO_OVERLAY set
+        3. call PgGetScalerCapabilities for info
+
+        problems:
+
+        1. Pg_VIDEO_OVERLAY is not defined in any
+           header files :)
+        2. PgVM_MODE_CAP1_VIDEO_OVERLAY is not set
+           even if the current mode supports overlay
+        3. the flags (chroma, etc) do not reflect
+           the actual capabilities 
+    */
+    
+    if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
+    {
+        if( ( p_vout->p_sys->p_channel = 
+            PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
+        {
+            intf_ErrMsg( "vout error: unable to create video channel" );
+            return( 1 );
+        }
+        else
+        {
+            int i = 0;
+            PgScalerCaps_t vcaps;
+
+            vcaps.size = sizeof( vcaps );
+            while( PgGetScalerCapabilities( p_vout->p_sys->p_channel, 
+                                            i++, &vcaps ) == 0 )
+            {    
+                if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
+                    vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
+                {
+                    p_vout->p_sys->i_vc_flags  = vcaps.flags;
+                    p_vout->p_sys->i_vc_format = vcaps.format;
+                }
+                
+                vcaps.size = sizeof( vcaps );
+            }
+
+            if( p_vout->p_sys->i_vc_format == 0 )
+            {
+                intf_ErrMsg( "vout error: need YV12 or RGB8888 overlay" );
+                return( 1 );
+            }
+            else if( vcaps.flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
+            {
+                color = PgGetOverlayChromaColor();
+            }
+        }
+    }
+
+    /* fullscreen, set dimension */
+    if( p_vout->b_fullscreen )
+    {
+        p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
+        p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
+        p_vout->i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
+        p_vout->i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
+    }
+
+    /* set window parameters */
+    PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
+    PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
+    PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
+    PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VideoLan Client", 0 );
+    PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
+    PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE, 
+                Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
+    PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
+        p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
+        Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
+
+    /* create window */
+    p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
+    if( p_vout->p_sys->p_window == NULL )
+    {
+        intf_ErrMsg( "vout error: unable to create window" );
+        return( 1 );
+    }
+
+    /* realize the window widget */
+    if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
+    {
+        intf_ErrMsg( "vout error: unable to realize window widget" );
+        PtDestroyWidget( p_vout->p_sys->p_window );
+        return( 1 );
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * QNXDestroyWnd: unrealize and destroy the main window
+ *****************************************************************************/
+static int QNXDestroyWnd( p_vout_thread_t p_vout )
+{
+    /* destroy the window widget */
+    PtUnrealizeWidget( p_vout->p_sys->p_window );
+    PtDestroyWidget( p_vout->p_sys->p_window );
+
+    /* destroy video channel */
+    if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
+    {
+        PgDestroyVideoChannel( p_vout->p_sys->p_channel );
+    }
+
+    return( 0 );
+}



