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