]> git.sesse.net Git - vlc/blob - plugins/qnx/vout_qnx.c
* QNX RTOS plug-in by Jon Lech Johansen.
[vlc] / plugins / qnx / vout_qnx.c
1 /*****************************************************************************
2  * vout_qnx.c: QNX RTOS video output display method
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  *
6  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #define MODULE_NAME qnx 
24 #include "modules_inner.h"
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "defs.h"
30
31 #include <errno.h>                                                 /* ENOMEM */
32 #include <stdlib.h>                                                /* free() */
33 #include <string.h>                                            /* strerror() */
34
35 #include <photon/PtWidget.h>
36 #include <photon/PtWindow.h>
37 #include <photon/PtLabel.h>
38 #include <photon/PdDirect.h>
39
40 #include "config.h"
41 #include "common.h"
42 #include "threads.h"
43 #include "mtime.h"
44 #include "tests.h"
45
46 #include "video.h"
47 #include "video_output.h"
48
49 #include "interface.h"
50 #include "intf_msg.h"
51 #include "main.h"
52
53 #include "modules.h"
54 #include "modules_export.h"
55
56 /*****************************************************************************
57  * vout_sys_t: video output QNX method descriptor
58  *****************************************************************************
59  * This structure is part of the video output thread descriptor.
60  * It describes the QNX specific properties of an output thread. QNX video
61  * output is performed through regular resizable windows. Windows can be
62  * dynamically resized to adapt to the size of the streams.
63  *****************************************************************************/
64
65 #define MODE_NORMAL_MEM     0
66 #define MODE_SHARED_MEM     1
67 #define MODE_VIDEO_MEM      2
68 #define MODE_VIDEO_OVERLAY  3
69
70 typedef struct vout_sys_s
71 {
72     /* video mode */
73     int                     i_mode;
74
75     /* internal stuff */
76     PtWidget_t *            p_window;
77
78     /* [shared] memory blit */
79     PhImage_t *             p_image[2];
80     int                     i_img_type;
81
82     /* video memory blit */
83     PdOffscreenContext_t *  p_ctx[2];
84     char *                  p_buf[2];
85
86     /* video overlay */
87     PgVideoChannel_t *      p_channel;
88     void *                  p_vc_y[2];
89     void *                  p_vc_u[2];
90     void *                  p_vc_v[2];
91     int                     i_vc_flags;
92     int                     i_vc_format;
93
94     /* position & dimensions */
95     PhPoint_t               pos;
96     PhDim_t                 dim;
97     PhDim_t                 old_dim;
98     PhDim_t                 screen_dim;
99 } vout_sys_t;
100
101 /*****************************************************************************
102  * Local prototypes
103  *****************************************************************************/
104 static int  vout_Probe     ( probedata_t *p_data );
105 static int  vout_Create    ( struct vout_thread_s * );
106 static int  vout_Init      ( struct vout_thread_s * );
107 static void vout_End       ( struct vout_thread_s * );
108 static void vout_Destroy   ( struct vout_thread_s * );
109 static int  vout_Manage    ( struct vout_thread_s * );
110 static void vout_Display   ( struct vout_thread_s * );
111
112 static int  QNXCreateWnd   ( struct vout_thread_s * );
113 static int  QNXDestroyWnd  ( struct vout_thread_s * );
114 static int  QNXInitDisplay ( struct vout_thread_s * );
115
116 /*****************************************************************************
117  * Functions exported as capabilities. They are declared as static so that
118  * we don't pollute the namespace too much.
119  *****************************************************************************/
120 void _M( vout_getfunctions )( function_list_t * p_function_list )
121 {
122     p_function_list->pf_probe = vout_Probe;
123     p_function_list->functions.vout.pf_create     = vout_Create;
124     p_function_list->functions.vout.pf_init       = vout_Init;
125     p_function_list->functions.vout.pf_end        = vout_End;
126     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
127     p_function_list->functions.vout.pf_manage     = vout_Manage;
128     p_function_list->functions.vout.pf_display    = vout_Display;
129     p_function_list->functions.vout.pf_setpalette = NULL;
130 }
131
132 /*****************************************************************************
133  * vout_Probe: probe the video driver and return a score
134  *****************************************************************************
135  * This function tries to initialize SDL and returns a score to the
136  * plugin manager so that it can select the best plugin.
137  *****************************************************************************/
138 static int vout_Probe( probedata_t *p_data )
139 {
140     if( TestMethod( VOUT_METHOD_VAR, "qnx" ) )
141     {
142         return( 999 );
143     }
144
145     return( 100 );
146 }
147
148 /*****************************************************************************
149  * vout_Create: allocate QNX video thread output method
150  *****************************************************************************
151  * This function allocate and initialize a QNX vout method. It uses some of the
152  * vout properties to choose the window size, and change them according to the
153  * actual properties of the display.
154  *****************************************************************************/
155 static int vout_Create( vout_thread_t *p_vout )
156 {
157     /* init connection to photon */
158     if( PtInit( "/dev/photon" ) != 0 )
159     {
160         intf_ErrMsg( "vout error: unable to connect to photon" );
161         return( 1 );
162     }
163
164     /* allocate structure */
165     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
166     if( p_vout->p_sys == NULL )
167     {
168         intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
169         return( 1 );
170     }
171
172     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
173
174     p_vout->b_fullscreen = 
175         main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
176     p_vout->p_sys->i_mode = 
177         main_GetIntVariable( VOUT_OVERLAY_VAR, VOUT_OVERLAY_DEFAULT ) ?
178         MODE_VIDEO_OVERLAY : MODE_NORMAL_MEM;
179     p_vout->p_sys->dim.w = 
180         main_GetIntVariable( VOUT_WIDTH_VAR, VOUT_WIDTH_DEFAULT );
181     p_vout->p_sys->dim.h = 
182         main_GetIntVariable( VOUT_HEIGHT_VAR, VOUT_HEIGHT_DEFAULT );
183     
184     /* init display and create window */
185     if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
186     {
187         free( p_vout->p_sys );
188         return( 1 );
189     }
190
191     return( 0 );
192 }
193
194 /*****************************************************************************
195  * vout_Init: initialize QNX video thread output method
196  *****************************************************************************
197  * This function create the buffers needed by the output thread. It is called
198  * at the beginning of the thread, but also each time the window is resized.
199  *****************************************************************************/
200 static int vout_Init( vout_thread_t *p_vout )
201 {
202     if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
203         p_vout->p_sys->i_mode == MODE_SHARED_MEM )
204     {
205         /* create images for [shared] memory blit */
206
207         if( !( p_vout->p_sys->p_image[0] = PhCreateImage( NULL,
208                     p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
209                     p_vout->p_sys->i_img_type, NULL, 0,
210                     p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
211             intf_ErrMsg( "vout error: cannot create image" );
212             return( 1 );
213         }
214
215         if( !( p_vout->p_sys->p_image[1] = PhCreateImage( NULL,
216                     p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
217                     p_vout->p_sys->i_img_type, NULL, 0,
218                     p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
219             intf_ErrMsg( "vout error: cannot create image" );
220             PhReleaseImage( p_vout->p_sys->p_image[0] );
221             free( p_vout->p_sys->p_image[0] );
222             p_vout->p_sys->p_image[0] = NULL;
223             return( 1 );
224         }
225         
226         /* set bytes per line, set buffers */
227         p_vout->i_bytes_per_line = p_vout->p_sys->p_image[0]->bpl;
228         p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_image[0]->image,
229                                  p_vout->p_sys->p_image[1]->image );
230     }
231     else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
232     {
233         /* create offscreen contexts for video memory blit */
234
235         if( ( p_vout->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
236                         p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
237                         Pg_OSC_MEM_PAGE_ALIGN ) ) == NULL )
238         {
239             intf_ErrMsg( "vout error: unable to create offscreen context" );
240             return( 1 );
241         }
242
243         if( ( p_vout->p_sys->p_ctx[1] = PdCreateOffscreenContext( 0,
244                         p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
245                         Pg_OSC_MEM_PAGE_ALIGN ) ) == NULL )
246         {
247             intf_ErrMsg( "vout error: unable to create offscreen context" );
248             PhDCRelease ( p_vout->p_sys->p_ctx[0] );
249             p_vout->p_sys->p_ctx[0] = NULL;
250             return( 1 );
251         }
252
253         /* get context pointers */
254         if( ( ( p_vout->p_sys->p_buf[0] =
255             PdGetOffscreenContextPtr ( p_vout->p_sys->p_ctx[0] ) ) == NULL ) ||
256             ( p_vout->p_sys->p_buf[1] =
257             PdGetOffscreenContextPtr ( p_vout->p_sys->p_ctx[1] ) ) == NULL )
258         {
259             intf_ErrMsg( "vout error: unable to get offscreen context ptr" );
260             PhDCRelease ( p_vout->p_sys->p_ctx[0] );
261             PhDCRelease ( p_vout->p_sys->p_ctx[1] );
262             p_vout->p_sys->p_ctx[0] = NULL;
263             p_vout->p_sys->p_ctx[1] = NULL;
264             return( 1 );
265         }
266
267         /* set bytes per line, clear buffers, set buffers */
268         p_vout->i_bytes_per_line = 
269             p_vout->i_bytes_per_pixel * p_vout->p_sys->dim.w;
270         memset( p_vout->p_sys->p_buf[0], 0,
271             p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
272         memset( p_vout->p_sys->p_buf[1], 0,
273             p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
274         p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_buf[0],
275                                  p_vout->p_sys->p_buf[1] );
276     }
277     else if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
278     {
279         PgScalerProps_t props;
280
281         props.size = sizeof( props );
282         props.format = p_vout->p_sys->i_vc_format; 
283         props.viewport.ul.x = p_vout->p_sys->pos.x + 4;
284         props.viewport.ul.y = p_vout->p_sys->pos.y + 20;
285         props.viewport.lr.x = p_vout->p_sys->dim.w + props.viewport.ul.x;
286         props.viewport.lr.y = p_vout->p_sys->dim.h + props.viewport.ul.y;
287         props.src_dim.w = p_vout->p_sys->dim.w;
288         props.src_dim.h    = p_vout->p_sys->dim.h;
289         props.flags = Pg_SCALER_PROP_SCALER_ENABLE |
290                       Pg_SCALER_PROP_DOUBLE_BUFFER;
291
292         if( PgConfigScalerChannel( p_vout->p_sys->p_channel, &props ) == -1 )
293         {
294             intf_ErrMsg( "vout error: unable to configure video channel" );
295             return( 1 );
296         }
297
298         p_vout->p_sys->p_vc_y[0] =
299             PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->yplane1 );
300         p_vout->p_sys->p_vc_y[1] =
301             PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->yplane2 );
302
303         if( p_vout->p_sys->p_vc_y[0] == NULL ||
304             p_vout->p_sys->p_vc_y[1] == NULL )
305         {
306             intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
307             return( 1 );
308         }
309
310         if( p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_YV12 )
311         {
312             p_vout->b_need_render = 0;
313
314             p_vout->p_sys->p_vc_u[0] =
315                 PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->uplane1 );
316             p_vout->p_sys->p_vc_u[1] =
317                 PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->uplane2 );
318             p_vout->p_sys->p_vc_v[0] =
319                 PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->vplane1 );
320             p_vout->p_sys->p_vc_v[1] =
321                 PdGetOffscreenContextPtr( p_vout->p_sys->p_channel->vplane2 );
322
323             if( p_vout->p_sys->p_vc_u[0] == NULL ||
324                 p_vout->p_sys->p_vc_u[1] == NULL ||
325                 p_vout->p_sys->p_vc_v[0] == NULL ||
326                 p_vout->p_sys->p_vc_v[1] == NULL )
327             {
328                 intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
329                 return( 1 );
330             }
331         }
332         else if( p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_RGB8888 )
333         {
334             /* set bytes per line, clear buffers, set buffers */
335             p_vout->i_bytes_per_line =
336                 p_vout->i_bytes_per_pixel * p_vout->p_sys->dim.w;
337             memset( p_vout->p_sys->p_vc_y[0], 0,
338                 p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
339             memset( p_vout->p_sys->p_vc_y[1], 0,
340                 p_vout->i_bytes_per_line * p_vout->p_sys->dim.h );
341             p_vout->pf_setbuffers( p_vout,
342                 p_vout->p_sys->p_vc_y[0], p_vout->p_sys->p_vc_y[1] );
343         }
344     }
345
346     return( 0 );
347 }
348
349 /*****************************************************************************
350  * vout_End: terminate QNX video thread output method
351  *****************************************************************************
352  * Destroy the buffers created by vout_Init. It is called at the end of
353  * the thread, but also each time the window is resized.
354  *****************************************************************************/
355 static void vout_End( vout_thread_t *p_vout )
356 {
357     if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
358         p_vout->p_sys->i_mode == MODE_SHARED_MEM ) && 
359         p_vout->p_sys->p_image[0] )
360     {
361         PhReleaseImage( p_vout->p_sys->p_image[0] );
362         PhReleaseImage( p_vout->p_sys->p_image[1] );
363         free( p_vout->p_sys->p_image[0] );
364         free( p_vout->p_sys->p_image[1] );
365     }
366     else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
367              p_vout->p_sys->p_ctx[0] )
368     {
369         PhDCRelease( p_vout->p_sys->p_ctx[0] );
370         PhDCRelease( p_vout->p_sys->p_ctx[1] );
371     }
372 }
373
374 /*****************************************************************************
375  * vout_Destroy: destroy QNX video thread output method
376  *****************************************************************************
377  * Terminate an output method created by vout_CreateOutputMethod
378  *****************************************************************************/
379 static void vout_Destroy( vout_thread_t *p_vout )
380 {
381     /* destroy the window */
382     QNXDestroyWnd( p_vout );
383
384     /* destroy structure */
385     free( p_vout->p_sys );
386 }
387
388 /*****************************************************************************
389  * vout_Manage: handle QNX events
390  *****************************************************************************
391  * This function should be called regularly by video output thread. It allows 
392  * window resizing. It returns a non null value on error.
393  *****************************************************************************/
394 static int vout_Manage( vout_thread_t *p_vout )
395 {
396     int i_ev, i_buflen;
397     PhEvent_t *p_event;
398     boolean_t b_repos = 0;
399
400     /* allocate buffer for event */
401     i_buflen = sizeof( PhEvent_t ) * 4;
402     if( ( p_event = malloc( i_buflen ) ) == NULL )
403     {
404         intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
405         return( 1 );
406     }
407
408     /* event loop */
409     do
410     {
411         memset( p_event, 0, i_buflen );
412         i_ev = PhEventPeek( p_event, i_buflen );
413
414         if( i_ev == Ph_RESIZE_MSG )
415         {
416             i_buflen = PhGetMsgSize( p_event );
417             if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
418             {
419                 intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
420                 return( 1 );
421             }
422         }
423         else if( i_ev == Ph_EVENT_MSG )
424         {
425             PtEventHandler( p_event );
426
427             if( p_event->type == Ph_EV_WM )
428             {
429                 PhWindowEvent_t *p_ev = PhGetData( p_event );
430
431                 switch( p_ev->event_f )
432                 {
433                 case Ph_WM_CLOSE:
434                     p_main->p_intf->b_die = 1;
435                     break;
436
437                 case Ph_WM_MOVE:
438                     b_repos = 1;
439                     p_vout->p_sys->pos.x = p_ev->pos.x;
440                     p_vout->p_sys->pos.y = p_ev->pos.y;
441                     break;
442
443                 case Ph_WM_RESIZE:
444                     p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
445                     p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
446                     p_vout->p_sys->dim.w = p_vout->i_width = p_ev->size.w;
447                     p_vout->p_sys->dim.h = p_vout->i_height = p_ev->size.h;
448                     p_vout->i_changes |= VOUT_SIZE_CHANGE;
449                     break;
450                 }
451             }
452             else if( p_event->type == Ph_EV_KEY )
453             {
454                 PhKeyEvent_t *p_ev = PhGetData( p_event );
455                 long i_key = p_ev->key_sym;
456
457                 if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
458                     ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
459                 {
460                     switch( i_key )
461                     {
462                     case Pk_q:
463                     case Pk_Q:
464                         p_main->p_intf->b_die = 1;
465                         break;
466
467                     case Pk_f:
468                     case Pk_F:
469                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
470                         break;
471
472                     case Pk_c:
473                     case Pk_C:
474                         p_vout->b_grayscale = ! p_vout->b_grayscale;
475                         p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
476                         break;
477
478                     default:
479                         if( i_key >= Pk_0 && i_key <= Pk_9 )
480                         {
481                             network_ChannelJoin( i_key );
482                         }
483                         else if( intf_ProcessKey( p_main->p_intf,
484                                                     (char) i_key ) )
485                         {
486                             intf_DbgMsg( "vout: unhandled key '%c' (%i)",
487                                          (char) i_key, i_key );
488                         }
489                         break;
490                     }
491                 }
492             }
493         }
494     } while( i_ev != -1 && i_ev != 0 );
495
496     free( p_event );
497
498     /*
499      * fullscreen
500      */ 
501     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
502     {
503         PhDim_t dim;
504         PhPoint_t pos;
505
506         intf_DbgMsg( "vout: changing full-screen status" );
507
508         p_vout->b_fullscreen = !p_vout->b_fullscreen;
509         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
510
511         if( p_vout->b_fullscreen )
512         {
513             pos.x = pos.y = 0;
514             dim.w = p_vout->p_sys->screen_dim.w + 1;
515             dim.h = p_vout->p_sys->screen_dim.h + 1;
516         }
517         else
518         {
519             pos.x = p_vout->p_sys->pos.x;
520             pos.y = p_vout->p_sys->pos.y;
521             dim.w = p_vout->p_sys->old_dim.w + 1;
522             dim.h = p_vout->p_sys->old_dim.h + 1;
523         }
524
525         PtSetResource( p_vout->p_sys->p_window,
526             Pt_ARG_WINDOW_RENDER_FLAGS,
527             p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
528             Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
529         PtSetResource( p_vout->p_sys->p_window,
530             Pt_ARG_POS, &pos, 0 );
531         PtSetResource( p_vout->p_sys->p_window,
532             Pt_ARG_DIM, &dim, 0 );
533     }
534
535     /*
536      * vout window resizing
537      */
538     if( ( p_vout->i_width  != p_vout->p_sys->dim.w ) ||
539              ( p_vout->i_height != p_vout->p_sys->dim.h ) )
540     {
541         intf_DbgMsg( "vout: resizing output window" );
542
543         p_vout->p_sys->dim.w = p_vout->i_width;
544         p_vout->p_sys->dim.h = p_vout->i_height;
545
546         /* set new dimension */
547         PtSetResource( p_vout->p_sys->p_window,
548             Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
549     }
550
551     /*
552      * size change
553      */
554     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
555     {
556         intf_DbgMsg( "vout: resizing window" );
557         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
558
559         vout_End( p_vout );
560         if( vout_Init( p_vout ) )
561         {
562             intf_ErrMsg( "vout error: cannot resize display" );
563             return( 1 );
564         }
565
566         p_vout->i_changes |= VOUT_YUV_CHANGE;
567         intf_Msg( "vout: video display resized (%dx%d)",
568                     p_vout->i_width, p_vout->i_height );
569     }
570
571     /*
572      * position change, move video channel
573      */
574     if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
575     {
576         intf_DbgMsg( "vout: moving video channel" );
577
578         vout_End( p_vout );
579         if( vout_Init( p_vout ) )
580         {
581             intf_ErrMsg( "vout error: unable to move video channel" );
582             return( 1 );
583         }
584     }
585
586     return( i_ev == -1 );
587 }
588
589 /*****************************************************************************
590  * vout_Display: displays previously rendered output
591  *****************************************************************************
592  * This function send the currently rendered image to QNX server, wait until
593  * it is displayed and switch the two rendering buffer, preparing next frame.
594  *****************************************************************************/
595 static void vout_Display( vout_thread_t *p_vout )
596 {
597     if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
598         p_vout->p_sys->i_mode == MODE_SHARED_MEM )
599     {
600         PhPoint_t pos = { 0, 0 };
601
602         PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
603         PgDrawPhImagemx( &pos, p_vout->p_sys->p_image[p_vout->i_buffer_index], 0 );
604         PgFlush();
605     }
606     else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
607     {
608         PhRect_t rc = { { 0, 0 }, { 
609                 p_vout->p_sys->dim.w,
610                 p_vout->p_sys->dim.h
611         } };
612
613         PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
614         PgContextBlit( p_vout->p_sys->p_ctx[p_vout->i_buffer_index], &rc, NULL, &rc );
615         PgFlush();
616     }
617     else if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY &&
618              p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_YV12 )
619     {
620         int i_size, i_index;
621
622         /* this code has NOT been tested */
623
624         i_size = p_vout->p_rendered_pic->i_width *
625                 p_vout->p_rendered_pic->i_height;
626         i_index = PgNextVideoFrame( p_vout->p_sys->p_channel );
627     
628         memcpy( p_vout->p_sys->p_vc_y[i_index],
629             p_vout->p_rendered_pic->p_y, i_size );
630         memcpy( p_vout->p_sys->p_vc_v[i_index],
631             p_vout->p_rendered_pic->p_v, i_size / 4 );
632         memcpy( p_vout->p_sys->p_vc_u[i_index],
633             p_vout->p_rendered_pic->p_u, i_size / 4 );
634     }
635 }
636
637 /*****************************************************************************
638  * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
639  *****************************************************************************/
640 static int QNXInitDisplay( p_vout_thread_t p_vout )
641 {
642     PgHWCaps_t hwcaps;
643     PgDisplaySettings_t cfg;
644     PgVideoModeInfo_t minfo;
645
646     /* get graphics card hw capabilities */
647     if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
648     {
649         intf_ErrMsg( "vout error: unable to get gfx card capabilities" );
650         return( 1 );
651     }
652
653     /* get current video mode */
654     if( PgGetVideoMode( &cfg ) != 0 )
655     {
656         intf_ErrMsg( "vout error: unable to get current video mode" );
657         return( 1 );
658     }
659
660     /* get video mode info */
661     if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
662     {
663         intf_ErrMsg( "vout error: unable to get info for video mode" );
664         return( 1 );
665     }
666
667     /* use video ram if we have enough available */
668     if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
669         hwcaps.currently_available_video_ram >= 
670         ( ( minfo.width * minfo.height * minfo.bits_per_pixel ) / 8 ) )
671     {
672         intf_DbgMsg( "vout: using video ram" );
673         p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
674     }
675
676     p_vout->p_sys->i_img_type = minfo.type;
677     p_vout->p_sys->screen_dim.w = minfo.width;
678     p_vout->p_sys->screen_dim.h = minfo.height;
679     p_vout->i_screen_depth = minfo.bits_per_pixel;
680
681     switch( minfo.type )
682     {
683         case Pg_IMAGE_PALETTE_BYTE:
684             p_vout->i_bytes_per_pixel = 1;
685             break;
686
687         case Pg_IMAGE_DIRECT_555:
688         case Pg_IMAGE_DIRECT_565:
689             p_vout->i_bytes_per_pixel = 2;
690             break;
691     
692         case Pg_IMAGE_DIRECT_8888:
693             p_vout->i_bytes_per_pixel = 4;
694             break;
695     }
696
697     switch( p_vout->i_screen_depth )
698     {
699         case 15:
700             p_vout->i_red_mask   = 0x7c00;
701             p_vout->i_green_mask = 0x03e0;
702             p_vout->i_blue_mask  = 0x001f;
703             break;
704
705         case 16:
706             p_vout->i_red_mask   = 0xf800;
707             p_vout->i_green_mask = 0x07e0;
708             p_vout->i_blue_mask  = 0x001f;
709             break;
710
711         case 24:
712         case 32:
713         default:
714             p_vout->i_red_mask   = 0xff0000;
715             p_vout->i_green_mask = 0x00ff00;
716             p_vout->i_blue_mask  = 0x0000ff;
717             break;
718     }
719
720     return( 0 );
721 }
722
723 /*****************************************************************************
724  * QNXCreateWnd: create and realize the main window
725  *****************************************************************************/
726 static int QNXCreateWnd( p_vout_thread_t p_vout )
727 {
728     PtArg_t args[8];
729     PhPoint_t pos = { 0, 0 };
730     PgColor_t color = Pg_BLACK;
731
732     /* correct way to check for overlay support:
733
734         1. call PgGetGraphicsHWCaps and check
735            the results for Pg_VIDEO_OVERLAY
736         2. check if the current graphics mode
737            has PgVM_MODE_CAP1_VIDEO_OVERLAY set
738         3. call PgGetScalerCapabilities for info
739
740         problems:
741
742         1. Pg_VIDEO_OVERLAY is not defined in any
743            header files :)
744         2. PgVM_MODE_CAP1_VIDEO_OVERLAY is not set
745            even if the current mode supports overlay
746         3. the flags (chroma, etc) do not reflect
747            the actual capabilities 
748     */
749     
750     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
751     {
752         if( ( p_vout->p_sys->p_channel = 
753             PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
754         {
755             intf_ErrMsg( "vout error: unable to create video channel" );
756             return( 1 );
757         }
758         else
759         {
760             int i = 0;
761             PgScalerCaps_t vcaps;
762
763             vcaps.size = sizeof( vcaps );
764             while( PgGetScalerCapabilities( p_vout->p_sys->p_channel, 
765                                             i++, &vcaps ) == 0 )
766             {    
767                 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
768                     vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
769                 {
770                     p_vout->p_sys->i_vc_flags  = vcaps.flags;
771                     p_vout->p_sys->i_vc_format = vcaps.format;
772                 }
773                 
774                 vcaps.size = sizeof( vcaps );
775             }
776
777             if( p_vout->p_sys->i_vc_format == 0 )
778             {
779                 intf_ErrMsg( "vout error: need YV12 or RGB8888 overlay" );
780                 return( 1 );
781             }
782             else if( vcaps.flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
783             {
784                 color = PgGetOverlayChromaColor();
785             }
786         }
787     }
788
789     /* fullscreen, set dimension */
790     if( p_vout->b_fullscreen )
791     {
792         p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
793         p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
794         p_vout->i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
795         p_vout->i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
796     }
797
798     /* set window parameters */
799     PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
800     PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
801     PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
802     PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VideoLan Client", 0 );
803     PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
804     PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE, 
805                 Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
806     PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
807         p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
808         Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
809
810     /* create window */
811     p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
812     if( p_vout->p_sys->p_window == NULL )
813     {
814         intf_ErrMsg( "vout error: unable to create window" );
815         return( 1 );
816     }
817
818     /* realize the window widget */
819     if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
820     {
821         intf_ErrMsg( "vout error: unable to realize window widget" );
822         PtDestroyWidget( p_vout->p_sys->p_window );
823         return( 1 );
824     }
825
826     return( 0 );
827 }
828
829 /*****************************************************************************
830  * QNXDestroyWnd: unrealize and destroy the main window
831  *****************************************************************************/
832 static int QNXDestroyWnd( p_vout_thread_t p_vout )
833 {
834     /* destroy the window widget */
835     PtUnrealizeWidget( p_vout->p_sys->p_window );
836     PtDestroyWidget( p_vout->p_sys->p_window );
837
838     /* destroy video channel */
839     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
840     {
841         PgDestroyVideoChannel( p_vout->p_sys->p_channel );
842     }
843
844     return( 0 );
845 }