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