]> git.sesse.net Git - vlc/blob - plugins/qnx/vout_qnx.c
* ./plugins/qnx/vout_qnx.c: port of the QNX vout plugin to the vout4 API,
[vlc] / plugins / qnx / vout_qnx.c
1 /*****************************************************************************
2  * vout_qnx.c: QNX RTOS video output display method
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  *
6  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
7  *          Pascal Levesque <Pascal.Levesque@mindready.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28 #include <stdlib.h>                                                /* free() */
29 #include <string.h>                                            /* strerror() */
30
31 #include <photon/PtWidget.h>
32 #include <photon/PtWindow.h>
33 #include <photon/PtLabel.h>
34 #include <photon/PdDirect.h>
35
36 #include <videolan/vlc.h>
37
38 #include "video.h"
39 #include "video_output.h"
40
41 #include "interface.h"
42
43 /*****************************************************************************
44  * vout_sys_t: video output QNX method descriptor
45  *****************************************************************************
46  * This structure is part of the video output thread descriptor.
47  * It describes the QNX specific properties of an output thread. QNX video
48  * output is performed through regular resizable windows. Windows can be
49  * dynamically resized to adapt to the size of the streams.
50  *****************************************************************************/
51 #define MAX_DIRECTBUFFERS 2
52
53 #define MODE_NORMAL_MEM     0
54 #define MODE_SHARED_MEM     1
55 #define MODE_VIDEO_MEM      2
56 #define MODE_VIDEO_OVERLAY  3
57
58 typedef struct vout_sys_s
59 {
60     /* video mode */
61     int                     i_mode;
62
63     /* internal stuff */
64     PtWidget_t *            p_window;
65
66     /* Color palette for 8bpp */
67     PgColor_t p_colors[255];
68
69     /* [shared] memory blit */
70     int                     i_img_type;
71
72     /* video memory blit */
73
74     /* video overlay */
75     PgVideoChannel_t *      p_channel;
76     int                     i_vc_flags;
77     int                     i_vc_format;
78
79     int                 i_screen_depth;
80     int                 i_bytes_per_pixel;
81     int                 i_bytes_per_line;
82
83     /* position & dimensions */
84     PhPoint_t               pos;
85     PhDim_t                 dim;
86     PhPoint_t               old_pos;
87     PhDim_t                 old_dim;
88     PhDim_t                 screen_dim;
89     PhRect_t                frame;
90 } vout_sys_t;
91
92
93 /*****************************************************************************
94  * picture_sys_t: direct buffer method descriptor
95  *****************************************************************************
96  * This structure is part of the picture descriptor, it describes the
97  * XVideo specific properties of a direct buffer.
98  *****************************************************************************/
99 typedef struct picture_sys_s
100 {
101     /* [shared] memory blit */
102     PhImage_t *             p_image;
103
104     /* video memory blit and video overlay */
105     PdOffscreenContext_t *  p_ctx[3];   /* 0: y, 1: u, 2: v */
106     char *                  p_buf[3];
107
108 } picture_sys_t;
109
110
111 /*****************************************************************************
112  * Local prototypes
113  *****************************************************************************/
114 static int  vout_Create    ( struct vout_thread_s * );
115 static int  vout_Init      ( struct vout_thread_s * );
116 static void vout_End       ( struct vout_thread_s * );
117 static void vout_Destroy   ( struct vout_thread_s * );
118 static int  vout_Manage    ( struct vout_thread_s * );
119 static void vout_Render    ( vout_thread_t *, picture_t * );
120 static void vout_Display   ( vout_thread_t *, picture_t * );
121
122 static int  QNXInitDisplay ( struct vout_thread_s * );
123 static int  QNXCreateWnd   ( struct vout_thread_s * );
124 static int  QNXDestroyWnd  ( struct vout_thread_s * );
125
126 static int  NewPicture     ( vout_thread_t *, picture_t *, int );
127 static void FreePicture    ( vout_thread_t *, picture_t * );
128 static int ResizeOverlayOutput ( vout_thread_t * );
129 static void SetPalette     ( vout_thread_t *, u16 *, u16 *, u16 * );
130
131 /*****************************************************************************
132  * Functions exported as capabilities. They are declared as static so that
133  * we don't pollute the namespace too much.
134  *****************************************************************************/
135 void _M( vout_getfunctions )( function_list_t * p_function_list )
136 {
137     p_function_list->functions.vout.pf_create     = vout_Create;
138     p_function_list->functions.vout.pf_init       = vout_Init;
139     p_function_list->functions.vout.pf_end        = vout_End;
140     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
141     p_function_list->functions.vout.pf_manage     = vout_Manage;
142     p_function_list->functions.vout.pf_render     = vout_Render;
143     p_function_list->functions.vout.pf_display    = vout_Display;
144 }
145
146 /*****************************************************************************
147  * vout_Create: allocate QNX video thread output method
148  *****************************************************************************
149  * This function allocate and initialize a QNX vout method. It uses some of the
150  * vout properties to choose the window size, and change them according to the
151  * actual properties of the display.
152  *****************************************************************************/
153 static int vout_Create( vout_thread_t *p_vout )
154 {
155     /* init connection to photon */
156     if( PtInit( "/dev/photon" ) != 0 )
157     {
158         intf_ErrMsg( "vout error: unable to connect to photon" );
159         return( 1 );
160     }
161
162     /* allocate structure */
163     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
164     if( p_vout->p_sys == NULL )
165     {
166         intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
167         return( 1 );
168     }
169
170     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
171
172     p_vout->b_fullscreen =
173         config_GetIntVariable( "fullscreen" );
174     p_vout->p_sys->i_mode =
175         config_GetIntVariable( "nooverlay" ) ?
176         MODE_NORMAL_MEM : MODE_VIDEO_OVERLAY;
177     p_vout->p_sys->dim.w = p_vout->i_window_width;
178     p_vout->p_sys->dim.h = p_vout->i_window_height;
179
180     /* init display and create window */
181     if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
182     {
183         free( p_vout->p_sys );
184         return( 1 );
185     }
186
187     return( 0 );
188 }
189
190 /*****************************************************************************
191  * vout_Init: initialize QNX video thread output method
192  *****************************************************************************
193  * This function create the buffers needed by the output thread. It is called
194  * at the beginning of the thread, but also each time the window is resized.
195  *****************************************************************************/
196 static int vout_Init( vout_thread_t *p_vout )
197 {
198     int i_index;
199     picture_t *p_pic;
200
201     I_OUTPUTPICTURES = 0;
202
203     switch( p_vout->p_sys->i_mode )
204     {
205     case MODE_NORMAL_MEM:
206     case MODE_SHARED_MEM:
207         p_vout->output.i_width = p_vout->p_sys->dim.w;
208         p_vout->output.i_height = p_vout->p_sys->dim.h;
209
210         /* Assume we have square pixels */
211         p_vout->output.i_aspect = p_vout->p_sys->dim.w
212                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
213         break;
214
215     case MODE_VIDEO_MEM:
216         p_vout->output.i_width = p_vout->p_sys->dim.w;
217         p_vout->output.i_height = p_vout->p_sys->dim.h;
218
219         /* Assume we have square pixels */
220         p_vout->output.i_aspect = p_vout->p_sys->dim.w
221                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
222         break;
223
224     case MODE_VIDEO_OVERLAY:
225         p_vout->output.i_width  = p_vout->render.i_width;
226         p_vout->output.i_height = p_vout->render.i_height;
227         p_vout->output.i_aspect = p_vout->render.i_aspect;
228
229         if (ResizeOverlayOutput(p_vout))
230         {
231             return (1);
232         }
233         break;
234
235     default:
236         /* This shouldn't happen ! */
237         break;
238     }
239
240     /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
241     while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
242     {
243         p_pic = NULL;
244
245         /* Find an empty picture slot */
246         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
247         {
248             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
249             {
250                 p_pic = p_vout->p_picture + i_index;
251                 break;
252             }
253         }
254
255         /* Allocate the picture */
256         if( p_pic == NULL || NewPicture( p_vout, p_pic, I_OUTPUTPICTURES ) )
257         {
258             break;
259         }
260
261         p_pic->i_status = DESTROYED_PICTURE;
262         p_pic->i_type   = DIRECT_PICTURE;
263
264         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
265
266         I_OUTPUTPICTURES++;
267     }
268
269     return( 0 );
270 }
271
272 /*****************************************************************************
273  * vout_End: terminate QNX video thread output method
274  *****************************************************************************
275  * Destroy the buffers created by vout_Init. It is called at the end of
276  * the thread, but also each time the window is resized.
277  *****************************************************************************/
278 static void vout_End( vout_thread_t *p_vout )
279 {
280     int i_index;
281
282     /* Free the direct buffers we allocated */
283     for( i_index = I_OUTPUTPICTURES ; i_index ; )
284     {
285         i_index--;
286         FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
287     }
288 }
289
290 /*****************************************************************************
291  * vout_Destroy: destroy QNX video thread output method
292  *****************************************************************************
293  * Terminate an output method created by vout_CreateOutputMethod
294  *****************************************************************************/
295 static void vout_Destroy( vout_thread_t *p_vout )
296 {
297     /* destroy the window */
298     QNXDestroyWnd( p_vout );
299
300     /* destroy structure */
301     free( p_vout->p_sys );
302 }
303
304 /*****************************************************************************
305  * vout_Manage: handle QNX events
306  *****************************************************************************
307  * This function should be called regularly by video output thread. It allows
308  * window resizing. It returns a non null value on error.
309  *****************************************************************************/
310 static int vout_Manage( vout_thread_t *p_vout )
311 {
312     int i_ev, i_buflen;
313     PhEvent_t *p_event;
314     boolean_t b_repos = 0;
315
316     if (p_vout->b_die == 1)
317     {
318         return ( 0 );
319     }
320
321     /* allocate buffer for event */
322     i_buflen = sizeof( PhEvent_t ) * 4;
323     if( ( p_event = malloc( i_buflen ) ) == NULL )
324     {
325         intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
326         return( 1 );
327     }
328
329     /* event loop */
330     do
331     {
332         memset( p_event, 0, i_buflen );
333         i_ev = PhEventPeek( p_event, i_buflen );
334
335         if( i_ev == Ph_RESIZE_MSG )
336         {
337             i_buflen = PhGetMsgSize( p_event );
338             if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
339             {
340                 intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
341                 return( 1 );
342             }
343         }
344         else if( i_ev == Ph_EVENT_MSG )
345         {
346             PtEventHandler( p_event );
347
348             if( p_event->type == Ph_EV_WM )
349             {
350                 PhWindowEvent_t *p_ev = PhGetData( p_event );
351
352                 switch( p_ev->event_f )
353                 {
354                 case Ph_WM_CLOSE:
355                     p_main->p_intf->b_die = 1;
356                     break;
357
358                 case Ph_WM_MOVE:
359                     p_vout->p_sys->pos.x = p_ev->pos.x;
360                     p_vout->p_sys->pos.y = p_ev->pos.y;
361                     b_repos = 1;
362                     break;
363
364                 case Ph_WM_RESIZE:
365                     p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
366                     p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
367                     p_vout->p_sys->dim.w = p_ev->size.w;
368                     p_vout->p_sys->dim.h = p_ev->size.h;
369                     p_vout->i_changes |= VOUT_SIZE_CHANGE;
370                     break;
371                 }
372             }
373             else if( p_event->type == Ph_EV_KEY )
374             {
375                 PhKeyEvent_t *p_ev = PhGetData( p_event );
376                 long i_key = p_ev->key_sym;
377
378                 if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
379                     ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
380                 {
381                     switch( i_key )
382                     {
383                     case Pk_q:
384                     case Pk_Q:
385                         p_main->p_intf->b_die = 1;
386                         break;
387
388                     case Pk_f:
389                     case Pk_F:
390                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
391                         break;
392
393                     case Pk_c:
394                     case Pk_C:
395                         p_vout->b_grayscale = ! p_vout->b_grayscale;
396                         p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
397                         break;
398
399                     default:
400                         if( i_key >= Pk_0 && i_key <= Pk_9 )
401                         {
402 //                            network_ChannelJoin( i_key );
403                         }
404                         break;
405                     }
406                 }
407             }
408         }
409     } while( i_ev != -1 && i_ev != 0 );
410
411     free( p_event );
412
413     /*
414      * fullscreen
415      */
416     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
417     {
418         PhDim_t dim;
419
420         p_vout->b_fullscreen = !p_vout->b_fullscreen;
421         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
422
423         if( p_vout->b_fullscreen )
424         {
425             p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x;
426             p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y;
427             p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0;
428             dim.w = p_vout->p_sys->screen_dim.w + 1;
429             dim.h = p_vout->p_sys->screen_dim.h + 1;
430         }
431         else
432         {
433             p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x;
434             p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y;
435             dim.w = p_vout->p_sys->old_dim.w + 1;
436             dim.h = p_vout->p_sys->old_dim.h + 1;
437         }
438
439         /* modify render flags, border */
440         PtSetResource( p_vout->p_sys->p_window,
441             Pt_ARG_WINDOW_RENDER_FLAGS,
442             p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
443             Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
444
445         /* set position and dimension */
446         PtSetResource( p_vout->p_sys->p_window,
447                        Pt_ARG_POS, &p_vout->p_sys->pos, 0 );
448         PtSetResource( p_vout->p_sys->p_window,
449                        Pt_ARG_DIM, &dim, 0 );
450
451         /* mark as damaged to force redraw */
452         PtDamageWidget( p_vout->p_sys->p_window );
453     }
454
455     /*
456      * size change
457      */
458     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
459     {
460         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
461
462         if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
463         {
464             ResizeOverlayOutput(p_vout);
465         }
466 #if 0
467         else
468         {
469             p_vout->output.i_width = p_vout->p_sys->dim.w;
470             p_vout->output.i_height = p_vout->p_sys->dim.h;
471             p_vout->i_changes |= VOUT_YUV_CHANGE;
472
473             vout_End( p_vout );
474             if( vout_Init( p_vout ) )
475             {
476                 intf_ErrMsg( "vout error: cannot resize display" );
477                 return( 1 );
478             }
479         }
480 #endif
481
482         intf_Msg( "vout: video display resized (%dx%d)",
483                   p_vout->p_sys->dim.w, p_vout->p_sys->dim.h );
484     }
485
486     /*
487      * position change, move video channel
488      */
489     if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
490     {
491         ResizeOverlayOutput(p_vout);
492     }
493
494     return( i_ev == -1 );
495 }
496
497 /*****************************************************************************
498  * vout_Render: render previously calculated output
499  *****************************************************************************/
500 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
501 {
502     ;
503 }
504
505 /*****************************************************************************
506  * vout_Display: displays previously rendered output
507  *****************************************************************************
508  * This function send the currently rendered image to QNX server, wait until
509  * it is displayed and switch the two rendering buffer, preparing next frame.
510  *****************************************************************************/
511 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
512 {
513     if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
514         p_vout->p_sys->i_mode == MODE_SHARED_MEM )
515     {
516         PhPoint_t pos = { 0, 0 };
517
518         PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
519         if (p_vout->p_sys->i_screen_depth == 8)
520         {
521             PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0);
522         }
523         PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 );
524         PgFlush();
525     }
526     else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
527     {
528         PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } };
529
530 //        PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
531         PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc );
532         PgFlush();
533     }
534 }
535
536 /*****************************************************************************
537  * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
538  *****************************************************************************/
539 static int QNXInitDisplay( p_vout_thread_t p_vout )
540 {
541     PgHWCaps_t hwcaps;
542     PgDisplaySettings_t cfg;
543     PgVideoModeInfo_t minfo;
544
545     /* get graphics card hw capabilities */
546     if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
547     {
548         intf_ErrMsg( "vout error: unable to get gfx card capabilities" );
549         return( 1 );
550     }
551
552     /* get current video mode */
553     if( PgGetVideoMode( &cfg ) != 0 )
554     {
555         intf_ErrMsg( "vout error: unable to get current video mode" );
556         return( 1 );
557     }
558
559     /* get video mode info */
560     if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
561     {
562         intf_ErrMsg( "vout error: unable to get info for video mode" );
563         return( 1 );
564     }
565
566     /* switch to normal mode if no overlay support */
567 //    printf("minfo.mode_capabilities1: 0x%x\n", minfo.mode_capabilities1);
568
569     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY &&
570         !( minfo.mode_capabilities1 & PgVM_MODE_CAP1_VIDEO_OVERLAY ) )
571     {
572         intf_ErrMsg( "vout error: no overlay support detected" );
573         p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
574     }
575
576     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
577     {
578         int i = 0;
579         PgScalerCaps_t vcaps;
580
581         if( ( p_vout->p_sys->p_channel =
582             PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
583         {
584             intf_ErrMsg( "vout error: unable to create video channel" );
585             printf("errno = %d\n", errno);
586             p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
587         }
588         else
589         {
590             vcaps.size = sizeof( vcaps );
591             while( PgGetScalerCapabilities( p_vout->p_sys->p_channel,
592                                             i++, &vcaps ) == 0 )
593             {
594                 printf("vcaps.format = 0x%x\n", vcaps.format);
595                 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
596                     vcaps.format == Pg_VIDEO_FORMAT_YUV420 ||
597                     vcaps.format == Pg_VIDEO_FORMAT_YUY2 ||
598                     vcaps.format == Pg_VIDEO_FORMAT_UYVY ||
599                     vcaps.format == Pg_VIDEO_FORMAT_RGB555 ||
600                     vcaps.format == Pg_VIDEO_FORMAT_RGB565 ||
601                     vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
602                 {
603                     p_vout->p_sys->i_vc_flags  = vcaps.flags;
604                     p_vout->p_sys->i_vc_format = vcaps.format;
605                 }
606
607                 vcaps.size = sizeof( vcaps );
608             }
609
610             if( p_vout->p_sys->i_vc_format == 0 )
611             {
612                 intf_ErrMsg( "vout error: need YV12, YUY2 or RGB8888 overlay" );
613
614                 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
615             }
616         }
617     }
618
619     /* use video ram if we have enough available */
620     if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
621         (minfo.bits_per_pixel != 8) &&
622         hwcaps.currently_available_video_ram >=
623         ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) )
624     {
625         p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
626         printf("Using video memory...\n");
627     }
628
629     p_vout->p_sys->i_img_type = minfo.type;
630     p_vout->p_sys->screen_dim.w = minfo.width;
631     p_vout->p_sys->screen_dim.h = minfo.height;
632     p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel;
633
634     switch( p_vout->p_sys->i_screen_depth )
635     {
636         case 8:
637             p_vout->output.i_chroma = FOURCC_RGB2;
638             p_vout->p_sys->i_bytes_per_pixel = 1;
639             p_vout->output.pf_setpalette = SetPalette;
640             break;
641
642         case 15:
643             p_vout->output.i_chroma = FOURCC_RV15;
644             p_vout->p_sys->i_bytes_per_pixel = 2;
645             p_vout->output.i_rmask = 0x7c00;
646             p_vout->output.i_gmask = 0x03e0;
647             p_vout->output.i_bmask = 0x001f;
648             break;
649
650         case 16:
651             p_vout->output.i_chroma = FOURCC_RV16;
652             p_vout->p_sys->i_bytes_per_pixel = 2;
653             p_vout->output.i_rmask = 0xf800;
654             p_vout->output.i_gmask = 0x07e0;
655             p_vout->output.i_bmask = 0x001f;
656             break;
657
658         case 24:
659             p_vout->output.i_chroma = FOURCC_RV24;
660             p_vout->p_sys->i_bytes_per_pixel = 3;
661             p_vout->output.i_rmask = 0xff0000;
662             p_vout->output.i_gmask = 0x00ff00;
663             p_vout->output.i_bmask = 0x0000ff;
664             break;
665
666         case 32:
667         default:
668             p_vout->output.i_chroma = FOURCC_RV32;
669             p_vout->p_sys->i_bytes_per_pixel = 4;
670             p_vout->output.i_rmask = 0xff0000;
671             p_vout->output.i_gmask = 0x00ff00;
672             p_vout->output.i_bmask = 0x0000ff;
673             break;
674     }
675
676     return( 0 );
677 }
678
679 /*****************************************************************************
680  * QNXCreateWnd: create and realize the main window
681  *****************************************************************************/
682 static int QNXCreateWnd( p_vout_thread_t p_vout )
683 {
684     PtArg_t args[8];
685     PhPoint_t pos = { 0, 0 };
686     PgColor_t color = Pg_BLACK;
687
688     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
689     {
690         if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
691         {
692             color = PgGetOverlayChromaColor();
693         }
694     }
695
696     /* fullscreen, set dimension */
697     if( p_vout->b_fullscreen )
698     {
699         p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
700         p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
701         p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
702         p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
703     }
704
705     /* set window parameters */
706     PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
707     PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
708     PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
709     PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VideoLan Client", 0 );
710     PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
711     PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
712               Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
713     PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
714               p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
715               Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
716
717     /* create window */
718     p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
719     if( p_vout->p_sys->p_window == NULL )
720     {
721         intf_ErrMsg( "vout error: unable to create window" );
722         return( 1 );
723     }
724
725     /* realize the window widget */
726     if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
727     {
728         intf_ErrMsg( "vout error: unable to realize window widget" );
729         PtDestroyWidget( p_vout->p_sys->p_window );
730         return( 1 );
731     }
732
733     /* get window frame size */
734     if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window,
735                            &p_vout->p_sys->frame ) != 0 )
736     {
737         intf_ErrMsg( "vout error: unable to get window frame size" );
738         PtDestroyWidget( p_vout->p_sys->p_window );
739         return( 1 );
740     }
741
742     return( 0 );
743 }
744
745 /*****************************************************************************
746  * QNXDestroyWnd: unrealize and destroy the main window
747  *****************************************************************************/
748 static int QNXDestroyWnd( p_vout_thread_t p_vout )
749 {
750     /* destroy the window widget */
751     PtUnrealizeWidget( p_vout->p_sys->p_window );
752 //    PtDestroyWidget( p_vout->p_sys->p_window );
753
754     /* destroy video channel */
755     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
756     {
757         PgDestroyVideoChannel( p_vout->p_sys->p_channel );
758     }
759
760     return( 0 );
761 }
762
763
764 /*****************************************************************************
765  * NewPicture: allocate a picture
766  *****************************************************************************
767  * Returns 0 on success, -1 otherwise
768  *****************************************************************************/
769 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index )
770 {
771     /* We know the chroma, allocate a buffer which will be used
772      * directly by the decoder */
773     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
774
775     if( p_pic->p_sys == NULL )
776     {
777         return -1;
778     }
779
780     switch( p_vout->p_sys->i_mode )
781     {
782     case MODE_NORMAL_MEM:
783     case MODE_SHARED_MEM:
784         /* create images for [shared] memory blit */
785         if( !( p_pic->p_sys->p_image = PhCreateImage( NULL,
786                     p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
787                     p_vout->p_sys->i_img_type, NULL, 0,
788                     p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
789             intf_ErrMsg( "vout error: cannot create image" );
790             free( p_pic->p_sys );
791             return( -1 );
792         }
793
794         p_pic->p->p_pixels = p_pic->p_sys->p_image->image;
795         p_pic->p->i_lines = p_pic->p_sys->p_image->size.h;
796         p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl;
797         p_pic->p->i_pixel_bytes = p_vout->p_sys->i_bytes_per_pixel;
798
799         if( p_pic->p->i_pitch == p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_image->size.w )
800         {
801             p_pic->p->b_margin = 0;
802         }
803         else
804         {
805             p_pic->p->b_margin = 1;
806             p_pic->p->b_hidden = 1;
807             p_pic->p->i_visible_bytes = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_image->size.w;
808         }
809
810         p_pic->i_planes = 1;
811         break;
812
813     case MODE_VIDEO_MEM:
814         /* create offscreen contexts for video memory blit */
815         if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
816                         p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
817                        Pg_OSC_MEM_PAGE_ALIGN) ) == NULL )
818         {
819             intf_ErrMsg( "vout error: unable to create offscreen context" );
820             free( p_pic->p_sys );
821             return( -1 );
822         }
823
824         /* get context pointers */
825         if( (  p_pic->p_sys->p_buf[0] =
826             PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL )
827         {
828             intf_ErrMsg( "vout error: unable to get offscreen context ptr" );
829             PhDCRelease ( p_pic->p_sys->p_ctx[0] );
830             p_pic->p_sys->p_ctx[0] = NULL;
831             free( p_pic->p_sys );
832             return( -1 );
833         }
834
835         p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch;
836         memset( p_pic->p_sys->p_buf[0], 0,
837             p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h );
838
839         p_pic->p->p_pixels = p_pic->p_sys->p_buf[0];
840         p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h;
841         p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch;
842         p_pic->p->i_pixel_bytes = p_vout->p_sys->i_bytes_per_pixel;
843
844         if( p_pic->p->i_pitch == p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_ctx[0]->dim.w )
845         {
846             p_pic->p->b_margin = 0;
847         }
848         else
849         {
850             p_pic->p->b_margin = 1;
851             p_pic->p->b_hidden = 1;
852             p_pic->p->i_visible_bytes = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_ctx[0]->dim.w;
853         }
854
855         p_pic->i_planes = 1;
856         break;
857
858     case MODE_VIDEO_OVERLAY:
859         if (index == 0)
860         {
861             p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1;
862             p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1;
863             p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1;
864         }
865         else
866         {
867             p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2;
868             p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2;
869             p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2;
870         }
871
872         p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] );
873         if( p_pic->p_sys->p_buf[Y_PLANE] == NULL )
874         {
875             intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
876             return( 1 );
877         }
878
879         switch (p_vout->p_sys->i_vc_format)
880         {
881             case Pg_VIDEO_FORMAT_YUV420:
882                 p_vout->output.i_chroma = FOURCC_I420;
883
884                 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
885                 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
886
887                 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
888                     p_pic->p_sys->p_buf[V_PLANE] == NULL )
889                 {
890                     intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
891                     return( 1 );
892                 }
893
894                 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
895                 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
896                 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
897                 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
898                 p_pic->p[Y_PLANE].b_margin = 0;
899
900                 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
901                 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
902                 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
903                 p_pic->p[U_PLANE].i_pixel_bytes = 1;
904                 p_pic->p[U_PLANE].b_margin = 0;
905
906                 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
907                 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
908                 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
909                 p_pic->p[V_PLANE].i_pixel_bytes = 1;
910                 p_pic->p[V_PLANE].b_margin = 0;
911
912                 p_pic->i_planes = 3;
913                 break;
914
915             case Pg_VIDEO_FORMAT_YV12:
916                 p_vout->output.i_chroma = FOURCC_YV12;
917
918                 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
919                 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
920
921                 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
922                     p_pic->p_sys->p_buf[V_PLANE] == NULL )
923                 {
924                     intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
925                     return( 1 );
926                 }
927
928                 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
929                 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
930                 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
931                 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
932                 p_pic->p[Y_PLANE].b_margin = 0;
933
934                 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
935                 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
936                 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
937                 p_pic->p[U_PLANE].i_pixel_bytes = 1;
938                 p_pic->p[U_PLANE].b_margin = 0;
939
940                 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
941                 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
942                 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
943                 p_pic->p[V_PLANE].i_pixel_bytes = 1;
944                 p_pic->p[V_PLANE].b_margin = 0;
945
946                 p_pic->i_planes = 3;
947                 break;
948
949             case Pg_VIDEO_FORMAT_UYVY:
950             case Pg_VIDEO_FORMAT_YUY2:
951                 if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY)
952                 {
953                     p_vout->output.i_chroma = FOURCC_UYVY;
954                 }
955                 else
956                 {
957                     p_vout->output.i_chroma = FOURCC_YUY2;
958                 }
959
960                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
961                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
962                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
963                 p_pic->p->i_pixel_bytes = 4;
964                 p_pic->p->b_margin = 0;
965
966                 p_pic->i_planes = 1;
967                 break;
968
969             case Pg_VIDEO_FORMAT_RGB555:
970                 p_vout->output.i_chroma = FOURCC_RV15;
971                 p_vout->output.i_rmask = 0x001f;
972                 p_vout->output.i_gmask = 0x03e0;
973                 p_vout->output.i_bmask = 0x7c00;
974
975                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
976                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
977                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
978                 p_pic->p->i_pixel_bytes = 2;
979
980                 if( p_pic->p->i_pitch == 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
981                 {
982                     p_pic->p->b_margin = 0;
983                 }
984                 else
985                 {
986                     p_pic->p->b_margin = 1;
987                     p_pic->p->b_hidden = 1;
988                     p_pic->p->i_visible_bytes = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
989                 }
990
991                 p_pic->i_planes = 1;
992                 break;
993
994             case Pg_VIDEO_FORMAT_RGB565:
995                 p_vout->output.i_chroma = FOURCC_RV16;
996                 p_vout->output.i_rmask = 0x001f;
997                 p_vout->output.i_gmask = 0x07e0;
998                 p_vout->output.i_bmask = 0xf800;
999
1000                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
1001                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
1002                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
1003                 p_pic->p->i_pixel_bytes = 4;
1004
1005                 if( p_pic->p->i_pitch == 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
1006                 {
1007                     p_pic->p->b_margin = 0;
1008                 }
1009                 else
1010                 {
1011                     p_pic->p->b_margin = 1;
1012                     p_pic->p->b_hidden = 1;
1013                     p_pic->p->i_visible_bytes = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
1014                 }
1015
1016                 p_pic->i_planes = 1;
1017                 break;
1018
1019             case Pg_VIDEO_FORMAT_RGB8888:
1020                 p_vout->output.i_chroma = FOURCC_RV32;
1021                 p_vout->output.i_rmask = 0x000000ff;
1022                 p_vout->output.i_gmask = 0x0000ff00;
1023                 p_vout->output.i_bmask = 0x00ff0000;
1024
1025                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
1026                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
1027                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
1028                 p_pic->p->i_pixel_bytes = 4;
1029
1030                 if( p_pic->p->i_pitch == 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
1031                 {
1032                     p_pic->p->b_margin = 0;
1033                 }
1034                 else
1035                 {
1036                     p_pic->p->b_margin = 1;
1037                     p_pic->p->b_hidden = 1;
1038                     p_pic->p->i_visible_bytes = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
1039                 }
1040
1041                 p_pic->i_planes = 1;
1042                 break;
1043         }
1044
1045 #if 0
1046     switch( p_vout->output.i_chroma )
1047     {
1048 #ifdef MODULE_NAME_IS_xvideo
1049         case FOURCC_Y211:
1050
1051             p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1052                                   + p_pic->p_sys->p_image->offsets[0];
1053             p_pic->p->i_lines = p_vout->output.i_height;
1054             /* XXX: this just looks so plain wrong... check it out ! */
1055             p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
1056             p_pic->p->i_pixel_bytes = 4;
1057             p_pic->p->b_margin = 0;
1058
1059             p_pic->i_planes = 1;
1060             break;
1061 #endif
1062
1063 #endif
1064
1065     default:
1066         /* This shouldn't happen ! */
1067         break;
1068     }
1069
1070     return 0;
1071 }
1072
1073 /*****************************************************************************
1074  * FreePicture: destroy a picture allocated with NewPicture
1075  *****************************************************************************
1076  * Destroy XImage AND associated data. If using Shm, detach shared memory
1077  * segment from server and process, then free it. The XDestroyImage manpage
1078  * says that both the image structure _and_ the data pointed to by the
1079  * image structure are freed, so no need to free p_image->data.
1080  *****************************************************************************/
1081 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1082 {
1083     if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
1084         p_vout->p_sys->i_mode == MODE_SHARED_MEM ) &&
1085         p_pic->p_sys->p_image )
1086     {
1087         PhReleaseImage( p_pic->p_sys->p_image );
1088         free( p_pic->p_sys->p_image );
1089     }
1090     else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
1091              p_pic->p_sys->p_ctx[0] )
1092     {
1093         PhDCRelease( p_pic->p_sys->p_ctx[0] );
1094     }
1095
1096     free( p_pic->p_sys );
1097 }
1098
1099
1100 static int ResizeOverlayOutput(vout_thread_t *p_vout)
1101 {
1102     int i_width, i_height, i_x, i_y;
1103     int i_ret;
1104     PgScalerProps_t props;
1105
1106     props.size   = sizeof( props );
1107     props.format = p_vout->p_sys->i_vc_format;
1108     props.flags  = Pg_SCALER_PROP_SCALER_ENABLE |
1109                           Pg_SCALER_PROP_DOUBLE_BUFFER;
1110
1111     /* enable chroma keying if available */
1112     if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
1113     {
1114         props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
1115     }
1116
1117     /* set viewport position */
1118     props.viewport.ul.x = p_vout->p_sys->pos.x;
1119     props.viewport.ul.y = p_vout->p_sys->pos.y;
1120     if( !p_vout->b_fullscreen )
1121     {
1122         props.viewport.ul.x += p_vout->p_sys->frame.ul.x;
1123         props.viewport.ul.y += p_vout->p_sys->frame.ul.y;
1124     }
1125
1126     /* set viewport dimension */
1127     vout_PlacePicture( p_vout, p_vout->p_sys->dim.w,
1128                            p_vout->p_sys->dim.h,
1129                            &i_x, &i_y, &i_width, &i_height );
1130
1131     props.viewport.ul.x += i_x;
1132     props.viewport.ul.y += i_y;
1133     props.viewport.lr.x = i_width + props.viewport.ul.x;
1134     props.viewport.lr.y = i_height + props.viewport.ul.y;
1135
1136     /* set source dimension */
1137     props.src_dim.w = p_vout->output.i_width;
1138     props.src_dim.h = p_vout->output.i_height;
1139
1140     /* configure scaler channel */
1141     i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props );
1142
1143     if( i_ret == -1 )
1144     {
1145         intf_ErrMsg( "vout error: unable to configure video channel" );
1146         return( 1 );
1147     }
1148
1149     return ( 0 );
1150 }
1151
1152
1153 /*****************************************************************************
1154  * SetPalette: sets an 8 bpp palette
1155  *****************************************************************************
1156  * This function sets the palette given as an argument. It does not return
1157  * anything, but could later send information on which colors it was unable
1158  * to set.
1159  *****************************************************************************/
1160 static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue )
1161 {
1162     int i;
1163
1164     /* allocate palette */
1165     for( i = 0; i < 255; i++ )
1166     {
1167         /* kludge: colors are indexed reversely because color 255 seems
1168          * to be reserved for black even if we try to set it to white */
1169         p_vout->p_sys->p_colors[ i ] = PgRGB( red[ i ] >> 8, green[ i ] >> 8, blue[ i ] >> 8 );
1170     }
1171 }