1 /*****************************************************************************
2 * vout_qnx.c: QNX RTOS video output display method
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
6 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
7 * Pascal Levesque <Pascal.Levesque@mindready.com>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <errno.h> /* ENOMEM */
28 #include <stdlib.h> /* free() */
29 #include <string.h> /* strerror() */
31 #include <photon/PtWidget.h>
32 #include <photon/PtWindow.h>
33 #include <photon/PtLabel.h>
34 #include <photon/PdDirect.h>
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
50 #define MODE_NORMAL_MEM 0
51 #define MODE_SHARED_MEM 1
52 #define MODE_VIDEO_MEM 2
53 #define MODE_VIDEO_OVERLAY 3
61 PtWidget_t * p_window;
63 /* Color palette for 8bpp */
64 PgColor_t p_colors[255];
66 /* [shared] memory blit */
69 /* video memory blit */
72 PgVideoChannel_t * p_channel;
77 int i_bytes_per_pixel;
80 /* position & dimensions */
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 *****************************************************************************/
98 /* [shared] memory blit */
101 /* video memory blit and video overlay */
102 PdOffscreenContext_t * p_ctx[3]; /* 0: y, 1: u, 2: v */
107 /*****************************************************************************
109 *****************************************************************************/
110 static int vout_Create ( vout_thread_t * );
111 static int vout_Init ( vout_thread_t * );
112 static void vout_End ( vout_thread_t * );
113 static void vout_Destroy ( vout_thread_t * );
114 static int vout_Manage ( vout_thread_t * );
115 static void vout_Render ( vout_thread_t *, picture_t * );
116 static void vout_Display ( vout_thread_t *, picture_t * );
118 static int QNXInitDisplay ( vout_thread_t * );
119 static int QNXCreateWnd ( vout_thread_t * );
120 static int QNXDestroyWnd ( vout_thread_t * );
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 *, u16 *, u16 *, u16 * );
127 /*****************************************************************************
128 * Functions exported as capabilities. They are declared as static so that
129 * we don't pollute the namespace too much.
130 *****************************************************************************/
131 void _M( vout_getfunctions )( function_list_t * p_function_list )
133 p_function_list->functions.vout.pf_create = vout_Create;
134 p_function_list->functions.vout.pf_init = vout_Init;
135 p_function_list->functions.vout.pf_end = vout_End;
136 p_function_list->functions.vout.pf_destroy = vout_Destroy;
137 p_function_list->functions.vout.pf_manage = vout_Manage;
138 p_function_list->functions.vout.pf_render = vout_Render;
139 p_function_list->functions.vout.pf_display = vout_Display;
142 /*****************************************************************************
143 * vout_Create: allocate QNX video thread output method
144 *****************************************************************************
145 * This function allocate and initialize a QNX vout method. It uses some of the
146 * vout properties to choose the window size, and change them according to the
147 * actual properties of the display.
148 *****************************************************************************/
149 static int vout_Create( vout_thread_t *p_vout )
151 /* init connection to photon */
152 if( PtInit( "/dev/photon" ) != 0 )
154 msg_Err( p_vout, "unable to connect to photon" );
158 /* allocate structure */
159 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
160 if( p_vout->p_sys == NULL )
162 msg_Err( p_vout, "out of memory" );
166 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
168 p_vout->b_fullscreen = config_GetInt( p_vout, "fullscreen" );
169 p_vout->p_sys->i_mode = config_GetInt( p_vout, "overlay" ) ?
170 MODE_VIDEO_OVERLAY : MODE_VIDEO_MEM;
171 p_vout->p_sys->dim.w = p_vout->i_window_width;
172 p_vout->p_sys->dim.h = p_vout->i_window_height;
174 /* init display and create window */
175 if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
177 free( p_vout->p_sys );
184 /*****************************************************************************
185 * vout_Init: initialize QNX video thread output method
186 *****************************************************************************
187 * This function create the buffers needed by the output thread. It is called
188 * at the beginning of the thread, but also each time the window is resized.
189 *****************************************************************************/
190 static int vout_Init( vout_thread_t *p_vout )
195 I_OUTPUTPICTURES = 0;
197 switch( p_vout->p_sys->i_mode )
199 case MODE_NORMAL_MEM:
200 case MODE_SHARED_MEM:
201 p_vout->output.i_width = p_vout->p_sys->dim.w;
202 p_vout->output.i_height = p_vout->p_sys->dim.h;
204 /* Assume we have square pixels */
205 p_vout->output.i_aspect = p_vout->p_sys->dim.w
206 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
210 p_vout->output.i_width = p_vout->p_sys->dim.w;
211 p_vout->output.i_height = p_vout->p_sys->dim.h;
213 /* Assume we have square pixels */
214 p_vout->output.i_aspect = p_vout->p_sys->dim.w
215 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
218 case MODE_VIDEO_OVERLAY:
219 p_vout->output.i_width = p_vout->render.i_width;
220 p_vout->output.i_height = p_vout->render.i_height;
221 p_vout->output.i_aspect = p_vout->render.i_aspect;
223 if (ResizeOverlayOutput(p_vout))
230 /* This shouldn't happen ! */
234 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
235 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
239 /* Find an empty picture slot */
240 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
242 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
244 p_pic = p_vout->p_picture + i_index;
249 /* Allocate the picture */
250 if( p_pic == NULL || NewPicture( p_vout, p_pic, I_OUTPUTPICTURES ) )
255 p_pic->i_status = DESTROYED_PICTURE;
256 p_pic->i_type = DIRECT_PICTURE;
258 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
266 /*****************************************************************************
267 * vout_End: terminate QNX video thread output method
268 *****************************************************************************
269 * Destroy the buffers created by vout_Init. It is called at the end of
270 * the thread, but also each time the window is resized.
271 *****************************************************************************/
272 static void vout_End( vout_thread_t *p_vout )
276 /* Free the direct buffers we allocated */
277 for( i_index = I_OUTPUTPICTURES ; i_index ; )
280 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
284 /*****************************************************************************
285 * vout_Destroy: destroy QNX video thread output method
286 *****************************************************************************
287 * Terminate an output method created by vout_CreateOutputMethod
288 *****************************************************************************/
289 static void vout_Destroy( vout_thread_t *p_vout )
291 /* destroy the window */
292 QNXDestroyWnd( p_vout );
294 /* destroy structure */
295 free( p_vout->p_sys );
298 /*****************************************************************************
299 * vout_Manage: handle QNX events
300 *****************************************************************************
301 * This function should be called regularly by video output thread. It allows
302 * window resizing. It returns a non null value on error.
303 *****************************************************************************/
304 static int vout_Manage( vout_thread_t *p_vout )
308 vlc_bool_t b_repos = 0;
310 if (p_vout->b_die == 1)
315 /* allocate buffer for event */
316 i_buflen = sizeof( PhEvent_t ) * 4;
317 if( ( p_event = malloc( i_buflen ) ) == NULL )
319 msg_Err( p_vout, "out of memory" );
326 memset( p_event, 0, i_buflen );
327 i_ev = PhEventPeek( p_event, i_buflen );
329 if( i_ev == Ph_RESIZE_MSG )
331 i_buflen = PhGetMsgSize( p_event );
332 if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
334 msg_Err( p_vout, "out of memory" );
338 else if( i_ev == Ph_EVENT_MSG )
340 PtEventHandler( p_event );
342 if( p_event->type == Ph_EV_WM )
344 PhWindowEvent_t *p_ev = PhGetData( p_event );
346 switch( p_ev->event_f )
349 p_vout->p_vlc->b_die = 1;
353 p_vout->p_sys->pos.x = p_ev->pos.x;
354 p_vout->p_sys->pos.y = p_ev->pos.y;
359 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
360 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
361 p_vout->p_sys->dim.w = p_ev->size.w;
362 p_vout->p_sys->dim.h = p_ev->size.h;
363 p_vout->i_changes |= VOUT_SIZE_CHANGE;
367 else if( p_event->type == Ph_EV_KEY )
369 PhKeyEvent_t *p_ev = PhGetData( p_event );
370 long i_key = p_ev->key_sym;
372 if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
373 ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
379 p_vout->p_vlc->b_die = 1;
384 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
389 p_vout->b_grayscale = ! p_vout->b_grayscale;
390 p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
394 if( i_key >= Pk_0 && i_key <= Pk_9 )
396 // network_ChannelJoin( i_key );
403 } while( i_ev != -1 && i_ev != 0 );
410 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
414 p_vout->b_fullscreen = !p_vout->b_fullscreen;
415 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
417 if( p_vout->b_fullscreen )
419 p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x;
420 p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y;
421 p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0;
422 dim.w = p_vout->p_sys->screen_dim.w + 1;
423 dim.h = p_vout->p_sys->screen_dim.h + 1;
427 p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x;
428 p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y;
429 dim.w = p_vout->p_sys->old_dim.w + 1;
430 dim.h = p_vout->p_sys->old_dim.h + 1;
433 /* modify render flags, border */
434 PtSetResource( p_vout->p_sys->p_window,
435 Pt_ARG_WINDOW_RENDER_FLAGS,
436 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
437 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
439 /* set position and dimension */
440 PtSetResource( p_vout->p_sys->p_window,
441 Pt_ARG_POS, &p_vout->p_sys->pos, 0 );
442 PtSetResource( p_vout->p_sys->p_window,
443 Pt_ARG_DIM, &dim, 0 );
445 /* mark as damaged to force redraw */
446 PtDamageWidget( p_vout->p_sys->p_window );
452 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
454 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
456 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
458 ResizeOverlayOutput(p_vout);
463 p_vout->output.i_width = p_vout->p_sys->dim.w;
464 p_vout->output.i_height = p_vout->p_sys->dim.h;
465 p_vout->i_changes |= VOUT_YUV_CHANGE;
468 if( vout_Init( p_vout ) )
470 msg_Err( p_vout, "cannot resize display" );
476 msg_Dbg( p_vout, "video display resized (%dx%d)",
477 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h );
481 * position change, move video channel
483 if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
485 ResizeOverlayOutput(p_vout);
488 return( i_ev == -1 );
491 /*****************************************************************************
492 * vout_Render: render previously calculated output
493 *****************************************************************************/
494 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
499 /*****************************************************************************
500 * vout_Display: displays previously rendered output
501 *****************************************************************************
502 * This function send the currently rendered image to QNX server, wait until
503 * it is displayed and switch the two rendering buffer, preparing next frame.
504 *****************************************************************************/
505 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
507 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
508 p_vout->p_sys->i_mode == MODE_SHARED_MEM )
510 PhPoint_t pos = { 0, 0 };
512 PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
513 if (p_vout->p_sys->i_screen_depth == 8)
515 PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0);
517 PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 );
520 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
522 PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } };
524 // PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
525 PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc );
530 /*****************************************************************************
531 * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
532 *****************************************************************************/
533 static int QNXInitDisplay( vout_thread_t * p_vout )
536 PgDisplaySettings_t cfg;
537 PgVideoModeInfo_t minfo;
539 /* get graphics card hw capabilities */
540 if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
542 msg_Err( p_vout, "unable to get gfx card capabilities" );
546 /* get current video mode */
547 if( PgGetVideoMode( &cfg ) != 0 )
549 msg_Err( p_vout, "unable to get current video mode" );
553 /* get video mode info */
554 if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
556 msg_Err( p_vout, "unable to get info for video mode" );
560 /* switch to normal mode if no overlay support */
561 // printf("minfo.mode_capabilities1: 0x%x\n", minfo.mode_capabilities1);
563 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY &&
564 !( minfo.mode_capabilities1 & PgVM_MODE_CAP1_VIDEO_OVERLAY ) )
566 msg_Err( p_vout, "no overlay support detected" );
567 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
570 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
573 PgScalerCaps_t vcaps;
575 if( ( p_vout->p_sys->p_channel =
576 PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
578 msg_Err( p_vout, "unable to create video channel" );
579 printf("errno = %d\n", errno);
580 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
584 vcaps.size = sizeof( vcaps );
585 while( PgGetScalerCapabilities( p_vout->p_sys->p_channel,
588 printf("vcaps.format = 0x%x\n", vcaps.format);
589 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
590 vcaps.format == Pg_VIDEO_FORMAT_YUV420 ||
591 vcaps.format == Pg_VIDEO_FORMAT_YUY2 ||
592 vcaps.format == Pg_VIDEO_FORMAT_UYVY ||
593 vcaps.format == Pg_VIDEO_FORMAT_RGB555 ||
594 vcaps.format == Pg_VIDEO_FORMAT_RGB565 ||
595 vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
597 p_vout->p_sys->i_vc_flags = vcaps.flags;
598 p_vout->p_sys->i_vc_format = vcaps.format;
601 vcaps.size = sizeof( vcaps );
604 if( p_vout->p_sys->i_vc_format == 0 )
606 msg_Warn( p_vout, "need YV12, YUY2 or RGB8888 overlay" );
608 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
613 /* use video ram if we have enough available */
614 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
615 (minfo.bits_per_pixel != 8) &&
616 hwcaps.currently_available_video_ram >=
617 ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) )
619 p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
620 printf("Using video memory...\n");
623 p_vout->p_sys->i_img_type = minfo.type;
624 p_vout->p_sys->screen_dim.w = minfo.width;
625 p_vout->p_sys->screen_dim.h = minfo.height;
626 p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel;
628 switch( p_vout->p_sys->i_screen_depth )
631 p_vout->output.i_chroma = FOURCC_RGB2;
632 p_vout->p_sys->i_bytes_per_pixel = 1;
633 p_vout->output.pf_setpalette = SetPalette;
637 p_vout->output.i_chroma = FOURCC_RV15;
638 p_vout->p_sys->i_bytes_per_pixel = 2;
639 p_vout->output.i_rmask = 0x7c00;
640 p_vout->output.i_gmask = 0x03e0;
641 p_vout->output.i_bmask = 0x001f;
645 p_vout->output.i_chroma = FOURCC_RV16;
646 p_vout->p_sys->i_bytes_per_pixel = 2;
647 p_vout->output.i_rmask = 0xf800;
648 p_vout->output.i_gmask = 0x07e0;
649 p_vout->output.i_bmask = 0x001f;
653 p_vout->output.i_chroma = FOURCC_RV24;
654 p_vout->p_sys->i_bytes_per_pixel = 3;
655 p_vout->output.i_rmask = 0xff0000;
656 p_vout->output.i_gmask = 0x00ff00;
657 p_vout->output.i_bmask = 0x0000ff;
662 p_vout->output.i_chroma = FOURCC_RV32;
663 p_vout->p_sys->i_bytes_per_pixel = 4;
664 p_vout->output.i_rmask = 0xff0000;
665 p_vout->output.i_gmask = 0x00ff00;
666 p_vout->output.i_bmask = 0x0000ff;
673 /*****************************************************************************
674 * QNXCreateWnd: create and realize the main window
675 *****************************************************************************/
676 static int QNXCreateWnd( vout_thread_t * p_vout )
679 PhPoint_t pos = { 0, 0 };
680 PgColor_t color = Pg_BLACK;
682 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
684 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
686 color = PgGetOverlayChromaColor();
690 /* fullscreen, set dimension */
691 if( p_vout->b_fullscreen )
693 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
694 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
695 p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
696 p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
699 /* set window parameters */
700 PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
701 PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
702 PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
703 PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VideoLan Client", 0 );
704 PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
705 PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
706 Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
707 PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
708 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
709 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
712 p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
713 if( p_vout->p_sys->p_window == NULL )
715 msg_Err( p_vout, "unable to create window" );
719 /* realize the window widget */
720 if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
722 msg_Err( p_vout, "unable to realize window widget" );
723 PtDestroyWidget( p_vout->p_sys->p_window );
727 /* get window frame size */
728 if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window,
729 &p_vout->p_sys->frame ) != 0 )
731 msg_Err( p_vout, "unable to get window frame size" );
732 PtDestroyWidget( p_vout->p_sys->p_window );
739 /*****************************************************************************
740 * QNXDestroyWnd: unrealize and destroy the main window
741 *****************************************************************************/
742 static int QNXDestroyWnd( vout_thread_t * p_vout )
744 /* destroy the window widget */
745 PtUnrealizeWidget( p_vout->p_sys->p_window );
746 // PtDestroyWidget( p_vout->p_sys->p_window );
748 /* destroy video channel */
749 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
751 PgDestroyVideoChannel( p_vout->p_sys->p_channel );
758 /*****************************************************************************
759 * NewPicture: allocate a picture
760 *****************************************************************************
761 * Returns 0 on success, -1 otherwise
762 *****************************************************************************/
763 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index )
765 /* We know the chroma, allocate a buffer which will be used
766 * directly by the decoder */
767 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
769 if( p_pic->p_sys == NULL )
774 switch( p_vout->p_sys->i_mode )
776 case MODE_NORMAL_MEM:
777 case MODE_SHARED_MEM:
778 /* create images for [shared] memory blit */
779 if( !( p_pic->p_sys->p_image = PhCreateImage( NULL,
780 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
781 p_vout->p_sys->i_img_type, NULL, 0,
782 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
783 msg_Err( p_vout, "cannot create image" );
784 free( p_pic->p_sys );
788 p_pic->p->p_pixels = p_pic->p_sys->p_image->image;
789 p_pic->p->i_lines = p_pic->p_sys->p_image->size.h;
790 p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl;
791 p_pic->p->i_pixel_bytes = p_vout->p_sys->i_bytes_per_pixel;
793 if( p_pic->p->i_pitch == p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_image->size.w )
795 p_pic->p->b_margin = 0;
799 p_pic->p->b_margin = 1;
800 p_pic->p->b_hidden = 1;
801 p_pic->p->i_visible_bytes = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_image->size.w;
808 /* create offscreen contexts for video memory blit */
809 if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
810 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
811 Pg_OSC_MEM_PAGE_ALIGN) ) == NULL )
813 msg_Err( p_vout, "unable to create offscreen context" );
814 free( p_pic->p_sys );
818 /* get context pointers */
819 if( ( p_pic->p_sys->p_buf[0] =
820 PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL )
822 msg_Err( p_vout, "unable to get offscreen context ptr" );
823 PhDCRelease ( p_pic->p_sys->p_ctx[0] );
824 p_pic->p_sys->p_ctx[0] = NULL;
825 free( p_pic->p_sys );
829 p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch;
830 memset( p_pic->p_sys->p_buf[0], 0,
831 p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h );
833 p_pic->p->p_pixels = p_pic->p_sys->p_buf[0];
834 p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h;
835 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch;
836 p_pic->p->i_pixel_bytes = p_vout->p_sys->i_bytes_per_pixel;
838 if( p_pic->p->i_pitch == p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_ctx[0]->dim.w )
840 p_pic->p->b_margin = 0;
844 p_pic->p->b_margin = 1;
845 p_pic->p->b_hidden = 1;
846 p_pic->p->i_visible_bytes = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_ctx[0]->dim.w;
852 case MODE_VIDEO_OVERLAY:
855 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1;
856 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1;
857 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1;
861 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2;
862 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2;
863 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2;
866 p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] );
867 if( p_pic->p_sys->p_buf[Y_PLANE] == NULL )
869 msg_Err( p_vout, "unable to get video channel ctx ptr" );
873 switch (p_vout->p_sys->i_vc_format)
875 case Pg_VIDEO_FORMAT_YUV420:
876 p_vout->output.i_chroma = FOURCC_I420;
878 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
879 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
881 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
882 p_pic->p_sys->p_buf[V_PLANE] == NULL )
884 msg_Err( p_vout, "unable to get video channel ctx ptr" );
888 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
889 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
890 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
891 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
892 p_pic->p[Y_PLANE].b_margin = 0;
894 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
895 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
896 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
897 p_pic->p[U_PLANE].i_pixel_bytes = 1;
898 p_pic->p[U_PLANE].b_margin = 0;
900 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
901 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
902 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
903 p_pic->p[V_PLANE].i_pixel_bytes = 1;
904 p_pic->p[V_PLANE].b_margin = 0;
909 case Pg_VIDEO_FORMAT_YV12:
910 p_vout->output.i_chroma = FOURCC_YV12;
912 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
913 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
915 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
916 p_pic->p_sys->p_buf[V_PLANE] == NULL )
918 msg_Err( p_vout, "unable to get video channel ctx ptr" );
922 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
923 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
924 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
925 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
926 p_pic->p[Y_PLANE].b_margin = 0;
928 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
929 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
930 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
931 p_pic->p[U_PLANE].i_pixel_bytes = 1;
932 p_pic->p[U_PLANE].b_margin = 0;
934 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
935 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
936 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
937 p_pic->p[V_PLANE].i_pixel_bytes = 1;
938 p_pic->p[V_PLANE].b_margin = 0;
943 case Pg_VIDEO_FORMAT_UYVY:
944 case Pg_VIDEO_FORMAT_YUY2:
945 if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY)
947 p_vout->output.i_chroma = FOURCC_UYVY;
951 p_vout->output.i_chroma = FOURCC_YUY2;
954 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
955 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
956 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
957 p_pic->p->i_pixel_bytes = 4;
958 p_pic->p->b_margin = 0;
963 case Pg_VIDEO_FORMAT_RGB555:
964 p_vout->output.i_chroma = FOURCC_RV15;
965 p_vout->output.i_rmask = 0x001f;
966 p_vout->output.i_gmask = 0x03e0;
967 p_vout->output.i_bmask = 0x7c00;
969 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
970 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
971 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
972 p_pic->p->i_pixel_bytes = 2;
974 if( p_pic->p->i_pitch == 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
976 p_pic->p->b_margin = 0;
980 p_pic->p->b_margin = 1;
981 p_pic->p->b_hidden = 1;
982 p_pic->p->i_visible_bytes = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
988 case Pg_VIDEO_FORMAT_RGB565:
989 p_vout->output.i_chroma = FOURCC_RV16;
990 p_vout->output.i_rmask = 0x001f;
991 p_vout->output.i_gmask = 0x07e0;
992 p_vout->output.i_bmask = 0xf800;
994 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
995 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
996 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
997 p_pic->p->i_pixel_bytes = 4;
999 if( p_pic->p->i_pitch == 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
1001 p_pic->p->b_margin = 0;
1005 p_pic->p->b_margin = 1;
1006 p_pic->p->b_hidden = 1;
1007 p_pic->p->i_visible_bytes = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
1010 p_pic->i_planes = 1;
1013 case Pg_VIDEO_FORMAT_RGB8888:
1014 p_vout->output.i_chroma = FOURCC_RV32;
1015 p_vout->output.i_rmask = 0x000000ff;
1016 p_vout->output.i_gmask = 0x0000ff00;
1017 p_vout->output.i_bmask = 0x00ff0000;
1019 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
1020 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
1021 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
1022 p_pic->p->i_pixel_bytes = 4;
1024 if( p_pic->p->i_pitch == 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
1026 p_pic->p->b_margin = 0;
1030 p_pic->p->b_margin = 1;
1031 p_pic->p->b_hidden = 1;
1032 p_pic->p->i_visible_bytes = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
1035 p_pic->i_planes = 1;
1040 switch( p_vout->output.i_chroma )
1042 #ifdef MODULE_NAME_IS_xvideo
1045 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1046 + p_pic->p_sys->p_image->offsets[0];
1047 p_pic->p->i_lines = p_vout->output.i_height;
1048 /* XXX: this just looks so plain wrong... check it out ! */
1049 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
1050 p_pic->p->i_pixel_bytes = 4;
1051 p_pic->p->b_margin = 0;
1053 p_pic->i_planes = 1;
1060 /* This shouldn't happen ! */
1067 /*****************************************************************************
1068 * FreePicture: destroy a picture allocated with NewPicture
1069 *****************************************************************************
1070 * Destroy XImage AND associated data. If using Shm, detach shared memory
1071 * segment from server and process, then free it. The XDestroyImage manpage
1072 * says that both the image structure _and_ the data pointed to by the
1073 * image structure are freed, so no need to free p_image->data.
1074 *****************************************************************************/
1075 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1077 if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
1078 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) &&
1079 p_pic->p_sys->p_image )
1081 PhReleaseImage( p_pic->p_sys->p_image );
1082 free( p_pic->p_sys->p_image );
1084 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
1085 p_pic->p_sys->p_ctx[0] )
1087 PhDCRelease( p_pic->p_sys->p_ctx[0] );
1090 free( p_pic->p_sys );
1094 static int ResizeOverlayOutput(vout_thread_t *p_vout)
1096 int i_width, i_height, i_x, i_y;
1098 PgScalerProps_t props;
1100 props.size = sizeof( props );
1101 props.format = p_vout->p_sys->i_vc_format;
1102 props.flags = Pg_SCALER_PROP_SCALER_ENABLE |
1103 Pg_SCALER_PROP_DOUBLE_BUFFER;
1105 /* enable chroma keying if available */
1106 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
1108 props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
1111 /* set viewport position */
1112 props.viewport.ul.x = p_vout->p_sys->pos.x;
1113 props.viewport.ul.y = p_vout->p_sys->pos.y;
1114 if( !p_vout->b_fullscreen )
1116 props.viewport.ul.x += p_vout->p_sys->frame.ul.x;
1117 props.viewport.ul.y += p_vout->p_sys->frame.ul.y;
1120 /* set viewport dimension */
1121 vout_PlacePicture( p_vout, p_vout->p_sys->dim.w,
1122 p_vout->p_sys->dim.h,
1123 &i_x, &i_y, &i_width, &i_height );
1125 props.viewport.ul.x += i_x;
1126 props.viewport.ul.y += i_y;
1127 props.viewport.lr.x = i_width + props.viewport.ul.x;
1128 props.viewport.lr.y = i_height + props.viewport.ul.y;
1130 /* set source dimension */
1131 props.src_dim.w = p_vout->output.i_width;
1132 props.src_dim.h = p_vout->output.i_height;
1134 /* configure scaler channel */
1135 i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props );
1139 msg_Err( p_vout, "unable to configure video channel" );
1147 /*****************************************************************************
1148 * SetPalette: sets an 8 bpp palette
1149 *****************************************************************************
1150 * This function sets the palette given as an argument. It does not return
1151 * anything, but could later send information on which colors it was unable
1153 *****************************************************************************/
1154 static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue )
1158 /* allocate palette */
1159 for( i = 0; i < 255; i++ )
1161 /* kludge: colors are indexed reversely because color 255 seems
1162 * to be reserved for black even if we try to set it to white */
1163 p_vout->p_sys->p_colors[ i ] = PgRGB( red[ i ] >> 8, green[ i ] >> 8, blue[ i ] >> 8 );