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