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