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