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