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