]> git.sesse.net Git - vlc/blob - modules/gui/qnx/vout.c
Merge branch 'master' of git@git.videolan.org:vlc
[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/vlc.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 E_(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 E_(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 (p_vout->b_die)
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                     case Pk_c:
382                     case Pk_C:
383                         p_vout->b_grayscale = ! p_vout->b_grayscale;
384                         p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
385                         break;
386
387                     default:
388                         break;
389                     }
390                 }
391             }
392         }
393     } while( i_ev != -1 && i_ev != 0 );
394
395     free( p_event );
396
397     /*
398      * fullscreen
399      */
400     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
401     {
402         PhDim_t dim;
403
404         p_vout->b_fullscreen = !p_vout->b_fullscreen;
405         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
406
407         if( p_vout->b_fullscreen )
408         {
409             p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x;
410             p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y;
411             p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0;
412             dim.w = p_vout->p_sys->screen_dim.w + 1;
413             dim.h = p_vout->p_sys->screen_dim.h + 1;
414         }
415         else
416         {
417             p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x;
418             p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y;
419             dim.w = p_vout->p_sys->old_dim.w + 1;
420             dim.h = p_vout->p_sys->old_dim.h + 1;
421         }
422
423         /* modify render flags, border */
424         PtSetResource( p_vout->p_sys->p_window,
425             Pt_ARG_WINDOW_RENDER_FLAGS,
426             p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
427             Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
428
429         /* set position and dimension */
430         PtSetResource( p_vout->p_sys->p_window,
431                        Pt_ARG_POS, &p_vout->p_sys->pos, 0 );
432         PtSetResource( p_vout->p_sys->p_window,
433                        Pt_ARG_DIM, &dim, 0 );
434
435         /* mark as damaged to force redraw */
436         PtDamageWidget( p_vout->p_sys->p_window );
437     }
438
439     /*
440      * size change
441      */
442     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
443     {
444         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
445
446         if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
447         {
448             ResizeOverlayOutput(p_vout);
449         }
450 #if 0
451         else
452         {
453             p_vout->output.i_width = p_vout->p_sys->dim.w;
454             p_vout->output.i_height = p_vout->p_sys->dim.h;
455             p_vout->i_changes |= VOUT_YUV_CHANGE;
456
457             QNXEnd( p_vout );
458             if( QNXInit( p_vout ) )
459             {
460                 msg_Err( p_vout, "cannot resize display" );
461                 return( 1 );
462             }
463         }
464 #endif
465
466         msg_Dbg( p_vout, "video display resized (%dx%d)",
467                          p_vout->p_sys->dim.w, p_vout->p_sys->dim.h );
468     }
469
470     /*
471      * position change, move video channel
472      */
473     if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
474     {
475         ResizeOverlayOutput(p_vout);
476     }
477
478     return( i_ev == -1 );
479 }
480
481 /*****************************************************************************
482  * QNXDisplay: displays previously rendered output
483  *****************************************************************************
484  * This function send the currently rendered image to QNX server, wait until
485  * it is displayed and switch the two rendering buffer, preparing next frame.
486  *****************************************************************************/
487 static void QNXDisplay( vout_thread_t *p_vout, picture_t *p_pic )
488 {
489     if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
490         p_vout->p_sys->i_mode == MODE_SHARED_MEM )
491     {
492         PhPoint_t pos = { 0, 0 };
493
494         PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
495         if (p_vout->p_sys->i_screen_depth == 8)
496         {
497             PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0);
498         }
499         PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 );
500         PgFlush();
501     }
502     else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
503     {
504         PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } };
505
506 //        PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
507         PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc );
508         PgFlush();
509     }
510 }
511
512 /*****************************************************************************
513  * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
514  *****************************************************************************/
515 static int QNXInitDisplay( vout_thread_t * p_vout )
516 {
517     PgHWCaps_t hwcaps;
518     PgDisplaySettings_t cfg;
519     PgVideoModeInfo_t minfo;
520
521     /* get graphics card hw capabilities */
522     if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
523     {
524         msg_Err( p_vout, "unable to get gfx card capabilities" );
525         return( 1 );
526     }
527
528     /* get current video mode */
529     if( PgGetVideoMode( &cfg ) != 0 )
530     {
531         msg_Err( p_vout, "unable to get current video mode" );
532         return( 1 );
533     }
534
535     /* get video mode info */
536     if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
537     {
538         msg_Err( p_vout, "unable to get info for video mode" );
539         return( 1 );
540     }
541
542     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
543     {
544         int i = 0;
545         PgScalerCaps_t vcaps;
546
547         if( ( p_vout->p_sys->p_channel =
548             PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
549         {
550             msg_Err( p_vout, "unable to create video channel" );
551             printf("errno = %d\n", errno);
552             p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
553         }
554         else
555         {
556             vcaps.size = sizeof( vcaps );
557             while( PgGetScalerCapabilities( p_vout->p_sys->p_channel,
558                                             i++, &vcaps ) == 0 )
559             {
560                 printf("vcaps.format = 0x%x\n", vcaps.format);
561                 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
562                     vcaps.format == Pg_VIDEO_FORMAT_YUV420 ||
563                     vcaps.format == Pg_VIDEO_FORMAT_YUY2 ||
564                     vcaps.format == Pg_VIDEO_FORMAT_UYVY ||
565                     vcaps.format == Pg_VIDEO_FORMAT_RGB555 ||
566                     vcaps.format == Pg_VIDEO_FORMAT_RGB565 ||
567                     vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
568                 {
569                     p_vout->p_sys->i_vc_flags  = vcaps.flags;
570                     p_vout->p_sys->i_vc_format = vcaps.format;
571                 }
572
573                 vcaps.size = sizeof( vcaps );
574             }
575
576             if( p_vout->p_sys->i_vc_format == 0 )
577             {
578                 msg_Warn( p_vout, "need YV12, YUY2 or RGB8888 overlay" );
579
580                 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
581             }
582         }
583     }
584
585     /* use video ram if we have enough available */
586     if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
587         (minfo.bits_per_pixel != 8) &&
588         hwcaps.currently_available_video_ram >=
589         ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) )
590     {
591         p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
592         printf("Using video memory...\n");
593     }
594
595     p_vout->p_sys->i_img_type = minfo.type;
596     p_vout->p_sys->screen_dim.w = minfo.width;
597     p_vout->p_sys->screen_dim.h = minfo.height;
598     p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel;
599
600     switch( p_vout->p_sys->i_screen_depth )
601     {
602         case 8:
603             p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
604             p_vout->p_sys->i_bytes_per_pixel = 1;
605             p_vout->output.pf_setpalette = SetPalette;
606             break;
607
608         case 15:
609             p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
610             p_vout->p_sys->i_bytes_per_pixel = 2;
611             p_vout->output.i_rmask = 0x7c00;
612             p_vout->output.i_gmask = 0x03e0;
613             p_vout->output.i_bmask = 0x001f;
614             break;
615
616         case 16:
617             p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
618             p_vout->p_sys->i_bytes_per_pixel = 2;
619             p_vout->output.i_rmask = 0xf800;
620             p_vout->output.i_gmask = 0x07e0;
621             p_vout->output.i_bmask = 0x001f;
622             break;
623
624         case 24:
625             p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
626             p_vout->p_sys->i_bytes_per_pixel = 3;
627             p_vout->output.i_rmask = 0xff0000;
628             p_vout->output.i_gmask = 0x00ff00;
629             p_vout->output.i_bmask = 0x0000ff;
630             break;
631
632         case 32:
633         default:
634             p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
635             p_vout->p_sys->i_bytes_per_pixel = 4;
636             p_vout->output.i_rmask = 0xff0000;
637             p_vout->output.i_gmask = 0x00ff00;
638             p_vout->output.i_bmask = 0x0000ff;
639             break;
640     }
641
642     return( 0 );
643 }
644
645 /*****************************************************************************
646  * QNXCreateWnd: create and realize the main window
647  *****************************************************************************/
648 static int QNXCreateWnd( vout_thread_t * p_vout )
649 {
650     PtArg_t args[8];
651     PhPoint_t pos = { 0, 0 };
652     PgColor_t color = Pg_BLACK;
653
654     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
655     {
656         if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
657         {
658             color = PgGetOverlayChromaColor();
659         }
660     }
661
662     /* fullscreen, set dimension */
663     if( p_vout->b_fullscreen )
664     {
665         p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
666         p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
667         p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
668         p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
669     }
670
671     /* set window parameters */
672     PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
673     PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
674     PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
675     PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VLC media player", 0 );
676     PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
677     PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
678               Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
679     PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
680               p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
681               Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
682
683     /* create window */
684     p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
685     if( p_vout->p_sys->p_window == NULL )
686     {
687         msg_Err( p_vout, "unable to create window" );
688         return( 1 );
689     }
690
691     /* realize the window widget */
692     if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
693     {
694         msg_Err( p_vout, "unable to realize window widget" );
695         PtDestroyWidget( p_vout->p_sys->p_window );
696         return( 1 );
697     }
698
699     /* get window frame size */
700     if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window,
701                            &p_vout->p_sys->frame ) != 0 )
702     {
703         msg_Err( p_vout, "unable to get window frame size" );
704         PtDestroyWidget( p_vout->p_sys->p_window );
705         return( 1 );
706     }
707
708     return( 0 );
709 }
710
711 /*****************************************************************************
712  * QNXDestroyWnd: unrealize and destroy the main window
713  *****************************************************************************/
714 static int QNXDestroyWnd( vout_thread_t * p_vout )
715 {
716     /* destroy the window widget */
717     PtUnrealizeWidget( p_vout->p_sys->p_window );
718 //    PtDestroyWidget( p_vout->p_sys->p_window );
719
720     /* destroy video channel */
721     if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
722     {
723         PgDestroyVideoChannel( p_vout->p_sys->p_channel );
724     }
725
726     return( 0 );
727 }
728
729
730 /*****************************************************************************
731  * NewPicture: allocate a picture
732  *****************************************************************************
733  * Returns 0 on success, -1 otherwise
734  *****************************************************************************/
735 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index )
736 {
737     /* We know the chroma, allocate a buffer which will be used
738      * directly by the decoder */
739     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
740
741     if( p_pic->p_sys == NULL )
742     {
743         return -1;
744     }
745
746     switch( p_vout->p_sys->i_mode )
747     {
748     case MODE_NORMAL_MEM:
749     case MODE_SHARED_MEM:
750         /* create images for [shared] memory blit */
751         if( !( p_pic->p_sys->p_image = PhCreateImage( NULL,
752                     p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
753                     p_vout->p_sys->i_img_type, NULL, 0,
754                     p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
755             msg_Err( p_vout, "cannot create image" );
756             free( p_pic->p_sys );
757             return( -1 );
758         }
759
760         p_pic->p->p_pixels = p_pic->p_sys->p_image->image;
761         p_pic->p->i_lines = p_pic->p_sys->p_image->size.h;
762         p_pic->p->i_visible_lines = p_pic->p_sys->p_image->size.h;
763         p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl;
764         p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
765         p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
766                                      * p_pic->p_sys->p_image->size.w;
767         p_pic->i_planes = 1;
768         break;
769
770     case MODE_VIDEO_MEM:
771         /* create offscreen contexts for video memory blit */
772         if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
773                         p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
774                        Pg_OSC_MEM_PAGE_ALIGN) ) == NULL )
775         {
776             msg_Err( p_vout, "unable to create offscreen context" );
777             free( p_pic->p_sys );
778             return( -1 );
779         }
780
781         /* get context pointers */
782         if( (  p_pic->p_sys->p_buf[0] =
783             PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL )
784         {
785             msg_Err( p_vout, "unable to get offscreen context ptr" );
786             PhDCRelease ( p_pic->p_sys->p_ctx[0] );
787             p_pic->p_sys->p_ctx[0] = NULL;
788             free( p_pic->p_sys );
789             return( -1 );
790         }
791
792         p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch;
793         memset( p_pic->p_sys->p_buf[0], 0,
794             p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h );
795
796         p_pic->p->p_pixels = p_pic->p_sys->p_buf[0];
797         p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h;
798         p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[0]->dim.h;
799         p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch;
800         p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
801         p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
802                                      * p_pic->p_sys->p_ctx[0]->dim.w;
803         p_pic->i_planes = 1;
804         break;
805
806     case MODE_VIDEO_OVERLAY:
807         if (index == 0)
808         {
809             p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1;
810             p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1;
811             p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1;
812         }
813         else
814         {
815             p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2;
816             p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2;
817             p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2;
818         }
819
820         p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] );
821         if( p_pic->p_sys->p_buf[Y_PLANE] == NULL )
822         {
823             msg_Err( p_vout, "unable to get video channel ctx ptr" );
824             return( 1 );
825         }
826
827         switch (p_vout->p_sys->i_vc_format)
828         {
829             case Pg_VIDEO_FORMAT_YUV420:
830                 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
831
832                 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
833                 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
834
835                 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
836                     p_pic->p_sys->p_buf[V_PLANE] == NULL )
837                 {
838                     msg_Err( p_vout, "unable to get video channel ctx ptr" );
839                     return( 1 );
840                 }
841
842                 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
843                 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
844                 p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
845                 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
846                 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
847                 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
848
849                 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
850                 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
851                 p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
852                 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
853                 p_pic->p[U_PLANE].i_pixel_pitch = 1;
854                 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
855
856                 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
857                 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
858                 p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
859                 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
860                 p_pic->p[V_PLANE].i_pixel_pitch = 1;
861                 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
862
863                 p_pic->i_planes = 3;
864                 break;
865
866             case Pg_VIDEO_FORMAT_YV12:
867                 p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
868
869                 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
870                 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
871
872                 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
873                     p_pic->p_sys->p_buf[V_PLANE] == NULL )
874                 {
875                     msg_Err( p_vout, "unable to get video channel ctx ptr" );
876                     return( 1 );
877                 }
878
879                 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
880                 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
881                 p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
882                 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
883                 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
884                 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
885
886                 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
887                 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
888                 p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
889                 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
890                 p_pic->p[U_PLANE].i_pixel_pitch = 1;
891                 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
892
893                 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
894                 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
895                 p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
896                 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
897                 p_pic->p[V_PLANE].i_pixel_pitch = 1;
898                 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
899
900                 p_pic->i_planes = 3;
901                 break;
902
903             case Pg_VIDEO_FORMAT_UYVY:
904             case Pg_VIDEO_FORMAT_YUY2:
905                 if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY)
906                 {
907                     p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
908                 }
909                 else
910                 {
911                     p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
912                 }
913
914                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
915                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
916                 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
917                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
918                 p_pic->p->i_pixel_pitch = 4;
919                 p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
920
921                 p_pic->i_planes = 1;
922                 break;
923
924             case Pg_VIDEO_FORMAT_RGB555:
925                 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
926                 p_vout->output.i_rmask = 0x001f;
927                 p_vout->output.i_gmask = 0x03e0;
928                 p_vout->output.i_bmask = 0x7c00;
929
930                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
931                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
932                 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
933                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
934                 p_pic->p->i_pixel_pitch = 2;
935                 p_pic->p->i_visible_pitch = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
936
937                 p_pic->i_planes = 1;
938                 break;
939
940             case Pg_VIDEO_FORMAT_RGB565:
941                 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
942                 p_vout->output.i_rmask = 0x001f;
943                 p_vout->output.i_gmask = 0x07e0;
944                 p_vout->output.i_bmask = 0xf800;
945
946                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
947                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
948                 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
949                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
950                 p_pic->p->i_pixel_pitch = 4;
951                 p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
952
953                 p_pic->i_planes = 1;
954                 break;
955
956             case Pg_VIDEO_FORMAT_RGB8888:
957                 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
958                 p_vout->output.i_rmask = 0x000000ff;
959                 p_vout->output.i_gmask = 0x0000ff00;
960                 p_vout->output.i_bmask = 0x00ff0000;
961
962                 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
963                 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
964                 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
965                 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
966                 p_pic->p->i_pixel_pitch = 4;
967                 p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
968
969                 p_pic->i_planes = 1;
970                 break;
971         }
972
973 #if 0
974     switch( p_vout->output.i_chroma )
975     {
976 #ifdef MODULE_NAME_IS_xvideo
977         case VLC_FOURCC('Y','2','1','1'):
978
979             p_pic->p->p_pixels = p_pic->p_sys->p_image->data
980                                   + p_pic->p_sys->p_image->offsets[0];
981             p_pic->p->i_lines = p_vout->output.i_height;
982             p_pic->p->i_visible_lines = p_vout->output.i_height;
983             /* XXX: this just looks so plain wrong... check it out ! */
984             p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
985             p_pic->p->i_pixel_pitch = 4;
986             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
987
988             p_pic->i_planes = 1;
989             break;
990 #endif
991
992 #endif
993
994     default:
995         /* This shouldn't happen ! */
996         break;
997     }
998
999     return 0;
1000 }
1001
1002 /*****************************************************************************
1003  * FreePicture: destroy a picture allocated with NewPicture
1004  *****************************************************************************
1005  * Destroy XImage AND associated data. If using Shm, detach shared memory
1006  * segment from server and process, then free it. The XDestroyImage manpage
1007  * says that both the image structure _and_ the data pointed to by the
1008  * image structure are freed, so no need to free p_image->data.
1009  *****************************************************************************/
1010 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1011 {
1012     if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
1013         p_vout->p_sys->i_mode == MODE_SHARED_MEM ) &&
1014         p_pic->p_sys->p_image )
1015     {
1016         PhReleaseImage( p_pic->p_sys->p_image );
1017         free( p_pic->p_sys->p_image );
1018     }
1019     else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
1020              p_pic->p_sys->p_ctx[0] )
1021     {
1022         PhDCRelease( p_pic->p_sys->p_ctx[0] );
1023     }
1024
1025     free( p_pic->p_sys );
1026 }
1027
1028
1029 static int ResizeOverlayOutput(vout_thread_t *p_vout)
1030 {
1031     int i_width, i_height, i_x, i_y;
1032     int i_ret;
1033     PgScalerProps_t props;
1034
1035     props.size   = sizeof( props );
1036     props.format = p_vout->p_sys->i_vc_format;
1037     props.flags  = Pg_SCALER_PROP_SCALER_ENABLE |
1038                           Pg_SCALER_PROP_DOUBLE_BUFFER;
1039
1040     /* enable chroma keying if available */
1041     if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
1042     {
1043         props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
1044     }
1045
1046     /* set viewport position */
1047     props.viewport.ul.x = p_vout->p_sys->pos.x;
1048     props.viewport.ul.y = p_vout->p_sys->pos.y;
1049     if( !p_vout->b_fullscreen )
1050     {
1051         props.viewport.ul.x += p_vout->p_sys->frame.ul.x;
1052         props.viewport.ul.y += p_vout->p_sys->frame.ul.y;
1053     }
1054
1055     /* set viewport dimension */
1056     vout_PlacePicture( p_vout, p_vout->p_sys->dim.w,
1057                            p_vout->p_sys->dim.h,
1058                            &i_x, &i_y, &i_width, &i_height );
1059
1060     props.viewport.ul.x += i_x;
1061     props.viewport.ul.y += i_y;
1062     props.viewport.lr.x = i_width + props.viewport.ul.x;
1063     props.viewport.lr.y = i_height + props.viewport.ul.y;
1064
1065     /* set source dimension */
1066     props.src_dim.w = p_vout->output.i_width;
1067     props.src_dim.h = p_vout->output.i_height;
1068
1069     /* configure scaler channel */
1070     i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props );
1071
1072     if( i_ret == -1 )
1073     {
1074         msg_Err( p_vout, "unable to configure video channel" );
1075         return( 1 );
1076     }
1077
1078     return ( 0 );
1079 }
1080
1081
1082 /*****************************************************************************
1083  * SetPalette: sets an 8 bpp palette
1084  *****************************************************************************
1085  * This function sets the palette given as an argument. It does not return
1086  * anything, but could later send information on which colors it was unable
1087  * to set.
1088  *****************************************************************************/
1089 static void SetPalette( vout_thread_t *p_vout,
1090                         uint16_t *red, uint16_t *green, uint16_t *blue )
1091 {
1092     int i;
1093
1094     /* allocate palette */
1095     for( i = 0; i < 255; i++ )
1096     {
1097         /* kludge: colors are indexed reversely because color 255 seems
1098          * to be reserved for black even if we try to set it to white */
1099         p_vout->p_sys->p_colors[ i ] = PgRGB( red[ i ] >> 8, green[ i ] >> 8, blue[ i ] >> 8 );
1100     }
1101 }