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 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 * );
115 static int QNXInitDisplay ( vout_thread_t * );
116 static int QNXCreateWnd ( vout_thread_t * );
117 static int QNXDestroyWnd ( vout_thread_t * );
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 *, u16 *, u16 *, u16 * );
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 )
133 vout_thread_t * p_vout = (vout_thread_t *)p_this;
135 /* init connection to photon */
136 if( PtInit( "/dev/photon" ) != 0 )
138 msg_Err( p_vout, "unable to connect to photon" );
142 /* allocate structure */
143 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
144 if( p_vout->p_sys == NULL )
146 msg_Err( p_vout, "out of memory" );
150 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
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;
158 /* init display and create window */
159 if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
161 free( p_vout->p_sys );
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;
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 )
185 I_OUTPUTPICTURES = 0;
187 switch( p_vout->p_sys->i_mode )
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;
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;
200 p_vout->output.i_width = p_vout->p_sys->dim.w;
201 p_vout->output.i_height = p_vout->p_sys->dim.h;
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;
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;
213 if (ResizeOverlayOutput(p_vout))
220 /* This shouldn't happen ! */
224 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
225 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
229 /* Find an empty picture slot */
230 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
232 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
234 p_pic = p_vout->p_picture + i_index;
239 /* Allocate the picture */
240 if( p_pic == NULL || NewPicture( p_vout, p_pic, I_OUTPUTPICTURES ) )
245 p_pic->i_status = DESTROYED_PICTURE;
246 p_pic->i_type = DIRECT_PICTURE;
248 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
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 )
266 /* Free the direct buffers we allocated */
267 for( i_index = I_OUTPUTPICTURES ; i_index ; )
270 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
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 )
281 vout_thread_t * p_vout = (vout_thread_t *)p_this;
283 /* destroy the window */
284 QNXDestroyWnd( p_vout );
286 /* destroy structure */
287 free( p_vout->p_sys );
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 )
300 vlc_bool_t b_repos = 0;
302 if (p_vout->b_die == 1)
307 /* allocate buffer for event */
308 i_buflen = sizeof( PhEvent_t ) * 4;
309 if( ( p_event = malloc( i_buflen ) ) == NULL )
311 msg_Err( p_vout, "out of memory" );
318 memset( p_event, 0, i_buflen );
319 i_ev = PhEventPeek( p_event, i_buflen );
321 if( i_ev == Ph_RESIZE_MSG )
323 i_buflen = PhGetMsgSize( p_event );
324 if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
326 msg_Err( p_vout, "out of memory" );
330 else if( i_ev == Ph_EVENT_MSG )
332 PtEventHandler( p_event );
334 if( p_event->type == Ph_EV_WM )
336 PhWindowEvent_t *p_ev = PhGetData( p_event );
338 switch( p_ev->event_f )
341 p_vout->p_vlc->b_die = 1;
345 p_vout->p_sys->pos.x = p_ev->pos.x;
346 p_vout->p_sys->pos.y = p_ev->pos.y;
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;
359 else if( p_event->type == Ph_EV_KEY )
361 PhKeyEvent_t *p_ev = PhGetData( p_event );
362 long i_key = p_ev->key_sym;
364 if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
365 ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
371 p_vout->p_vlc->b_die = 1;
376 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
381 p_vout->b_grayscale = ! p_vout->b_grayscale;
382 p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
386 if( i_key >= Pk_0 && i_key <= Pk_9 )
388 // network_ChannelJoin( i_key );
395 } while( i_ev != -1 && i_ev != 0 );
402 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
406 p_vout->b_fullscreen = !p_vout->b_fullscreen;
407 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
409 if( p_vout->b_fullscreen )
411 p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x;
412 p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y;
413 p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0;
414 dim.w = p_vout->p_sys->screen_dim.w + 1;
415 dim.h = p_vout->p_sys->screen_dim.h + 1;
419 p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x;
420 p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y;
421 dim.w = p_vout->p_sys->old_dim.w + 1;
422 dim.h = p_vout->p_sys->old_dim.h + 1;
425 /* modify render flags, border */
426 PtSetResource( p_vout->p_sys->p_window,
427 Pt_ARG_WINDOW_RENDER_FLAGS,
428 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
429 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
431 /* set position and dimension */
432 PtSetResource( p_vout->p_sys->p_window,
433 Pt_ARG_POS, &p_vout->p_sys->pos, 0 );
434 PtSetResource( p_vout->p_sys->p_window,
435 Pt_ARG_DIM, &dim, 0 );
437 /* mark as damaged to force redraw */
438 PtDamageWidget( p_vout->p_sys->p_window );
444 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
446 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
448 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
450 ResizeOverlayOutput(p_vout);
455 p_vout->output.i_width = p_vout->p_sys->dim.w;
456 p_vout->output.i_height = p_vout->p_sys->dim.h;
457 p_vout->i_changes |= VOUT_YUV_CHANGE;
460 if( QNXInit( p_vout ) )
462 msg_Err( p_vout, "cannot resize display" );
468 msg_Dbg( p_vout, "video display resized (%dx%d)",
469 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h );
473 * position change, move video channel
475 if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
477 ResizeOverlayOutput(p_vout);
480 return( i_ev == -1 );
483 /*****************************************************************************
484 * QNXDisplay: displays previously rendered output
485 *****************************************************************************
486 * This function send the currently rendered image to QNX server, wait until
487 * it is displayed and switch the two rendering buffer, preparing next frame.
488 *****************************************************************************/
489 static void QNXDisplay( vout_thread_t *p_vout, picture_t *p_pic )
491 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
492 p_vout->p_sys->i_mode == MODE_SHARED_MEM )
494 PhPoint_t pos = { 0, 0 };
496 PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
497 if (p_vout->p_sys->i_screen_depth == 8)
499 PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0);
501 PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 );
504 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
506 PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } };
508 // PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
509 PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc );
514 /*****************************************************************************
515 * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
516 *****************************************************************************/
517 static int QNXInitDisplay( vout_thread_t * p_vout )
520 PgDisplaySettings_t cfg;
521 PgVideoModeInfo_t minfo;
523 /* get graphics card hw capabilities */
524 if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
526 msg_Err( p_vout, "unable to get gfx card capabilities" );
530 /* get current video mode */
531 if( PgGetVideoMode( &cfg ) != 0 )
533 msg_Err( p_vout, "unable to get current video mode" );
537 /* get video mode info */
538 if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
540 msg_Err( p_vout, "unable to get info for video mode" );
544 /* switch to normal mode if no overlay support */
545 // printf("minfo.mode_capabilities1: 0x%x\n", minfo.mode_capabilities1);
547 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY &&
548 !( minfo.mode_capabilities1 & PgVM_MODE_CAP1_VIDEO_OVERLAY ) )
550 msg_Err( p_vout, "no overlay support detected" );
551 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
554 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
557 PgScalerCaps_t vcaps;
559 if( ( p_vout->p_sys->p_channel =
560 PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
562 msg_Err( p_vout, "unable to create video channel" );
563 printf("errno = %d\n", errno);
564 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
568 vcaps.size = sizeof( vcaps );
569 while( PgGetScalerCapabilities( p_vout->p_sys->p_channel,
572 printf("vcaps.format = 0x%x\n", vcaps.format);
573 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
574 vcaps.format == Pg_VIDEO_FORMAT_YUV420 ||
575 vcaps.format == Pg_VIDEO_FORMAT_YUY2 ||
576 vcaps.format == Pg_VIDEO_FORMAT_UYVY ||
577 vcaps.format == Pg_VIDEO_FORMAT_RGB555 ||
578 vcaps.format == Pg_VIDEO_FORMAT_RGB565 ||
579 vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
581 p_vout->p_sys->i_vc_flags = vcaps.flags;
582 p_vout->p_sys->i_vc_format = vcaps.format;
585 vcaps.size = sizeof( vcaps );
588 if( p_vout->p_sys->i_vc_format == 0 )
590 msg_Warn( p_vout, "need YV12, YUY2 or RGB8888 overlay" );
592 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
597 /* use video ram if we have enough available */
598 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
599 (minfo.bits_per_pixel != 8) &&
600 hwcaps.currently_available_video_ram >=
601 ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) )
603 p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
604 printf("Using video memory...\n");
607 p_vout->p_sys->i_img_type = minfo.type;
608 p_vout->p_sys->screen_dim.w = minfo.width;
609 p_vout->p_sys->screen_dim.h = minfo.height;
610 p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel;
612 switch( p_vout->p_sys->i_screen_depth )
615 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
616 p_vout->p_sys->i_bytes_per_pixel = 1;
617 p_vout->output.pf_setpalette = SetPalette;
621 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
622 p_vout->p_sys->i_bytes_per_pixel = 2;
623 p_vout->output.i_rmask = 0x7c00;
624 p_vout->output.i_gmask = 0x03e0;
625 p_vout->output.i_bmask = 0x001f;
629 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
630 p_vout->p_sys->i_bytes_per_pixel = 2;
631 p_vout->output.i_rmask = 0xf800;
632 p_vout->output.i_gmask = 0x07e0;
633 p_vout->output.i_bmask = 0x001f;
637 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
638 p_vout->p_sys->i_bytes_per_pixel = 3;
639 p_vout->output.i_rmask = 0xff0000;
640 p_vout->output.i_gmask = 0x00ff00;
641 p_vout->output.i_bmask = 0x0000ff;
646 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
647 p_vout->p_sys->i_bytes_per_pixel = 4;
648 p_vout->output.i_rmask = 0xff0000;
649 p_vout->output.i_gmask = 0x00ff00;
650 p_vout->output.i_bmask = 0x0000ff;
657 /*****************************************************************************
658 * QNXCreateWnd: create and realize the main window
659 *****************************************************************************/
660 static int QNXCreateWnd( vout_thread_t * p_vout )
663 PhPoint_t pos = { 0, 0 };
664 PgColor_t color = Pg_BLACK;
666 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
668 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
670 color = PgGetOverlayChromaColor();
674 /* fullscreen, set dimension */
675 if( p_vout->b_fullscreen )
677 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
678 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
679 p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
680 p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
683 /* set window parameters */
684 PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
685 PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
686 PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
687 PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VideoLan Client", 0 );
688 PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
689 PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
690 Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
691 PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
692 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
693 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
696 p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
697 if( p_vout->p_sys->p_window == NULL )
699 msg_Err( p_vout, "unable to create window" );
703 /* realize the window widget */
704 if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
706 msg_Err( p_vout, "unable to realize window widget" );
707 PtDestroyWidget( p_vout->p_sys->p_window );
711 /* get window frame size */
712 if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window,
713 &p_vout->p_sys->frame ) != 0 )
715 msg_Err( p_vout, "unable to get window frame size" );
716 PtDestroyWidget( p_vout->p_sys->p_window );
723 /*****************************************************************************
724 * QNXDestroyWnd: unrealize and destroy the main window
725 *****************************************************************************/
726 static int QNXDestroyWnd( vout_thread_t * p_vout )
728 /* destroy the window widget */
729 PtUnrealizeWidget( p_vout->p_sys->p_window );
730 // PtDestroyWidget( p_vout->p_sys->p_window );
732 /* destroy video channel */
733 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
735 PgDestroyVideoChannel( p_vout->p_sys->p_channel );
742 /*****************************************************************************
743 * NewPicture: allocate a picture
744 *****************************************************************************
745 * Returns 0 on success, -1 otherwise
746 *****************************************************************************/
747 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index )
749 /* We know the chroma, allocate a buffer which will be used
750 * directly by the decoder */
751 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
753 if( p_pic->p_sys == NULL )
758 switch( p_vout->p_sys->i_mode )
760 case MODE_NORMAL_MEM:
761 case MODE_SHARED_MEM:
762 /* create images for [shared] memory blit */
763 if( !( p_pic->p_sys->p_image = PhCreateImage( NULL,
764 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
765 p_vout->p_sys->i_img_type, NULL, 0,
766 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
767 msg_Err( p_vout, "cannot create image" );
768 free( p_pic->p_sys );
772 p_pic->p->p_pixels = p_pic->p_sys->p_image->image;
773 p_pic->p->i_lines = p_pic->p_sys->p_image->size.h;
774 p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl;
775 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
776 p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
777 * p_pic->p_sys->p_image->size.w;
782 /* create offscreen contexts for video memory blit */
783 if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
784 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
785 Pg_OSC_MEM_PAGE_ALIGN) ) == NULL )
787 msg_Err( p_vout, "unable to create offscreen context" );
788 free( p_pic->p_sys );
792 /* get context pointers */
793 if( ( p_pic->p_sys->p_buf[0] =
794 PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL )
796 msg_Err( p_vout, "unable to get offscreen context ptr" );
797 PhDCRelease ( p_pic->p_sys->p_ctx[0] );
798 p_pic->p_sys->p_ctx[0] = NULL;
799 free( p_pic->p_sys );
803 p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch;
804 memset( p_pic->p_sys->p_buf[0], 0,
805 p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h );
807 p_pic->p->p_pixels = p_pic->p_sys->p_buf[0];
808 p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h;
809 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch;
810 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
811 p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
812 * p_pic->p_sys->p_ctx[0]->dim.w;
816 case MODE_VIDEO_OVERLAY:
819 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1;
820 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1;
821 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1;
825 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2;
826 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2;
827 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2;
830 p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] );
831 if( p_pic->p_sys->p_buf[Y_PLANE] == NULL )
833 msg_Err( p_vout, "unable to get video channel ctx ptr" );
837 switch (p_vout->p_sys->i_vc_format)
839 case Pg_VIDEO_FORMAT_YUV420:
840 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
842 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
843 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
845 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
846 p_pic->p_sys->p_buf[V_PLANE] == NULL )
848 msg_Err( p_vout, "unable to get video channel ctx ptr" );
852 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
853 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
854 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
855 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
856 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
858 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
859 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
860 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
861 p_pic->p[U_PLANE].i_pixel_pitch = 1;
862 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
864 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
865 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
866 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
867 p_pic->p[V_PLANE].i_pixel_pitch = 1;
868 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
873 case Pg_VIDEO_FORMAT_YV12:
874 p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
876 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
877 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
879 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
880 p_pic->p_sys->p_buf[V_PLANE] == NULL )
882 msg_Err( p_vout, "unable to get video channel ctx ptr" );
886 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
887 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
888 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
889 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
890 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
892 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
893 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
894 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
895 p_pic->p[U_PLANE].i_pixel_pitch = 1;
896 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
898 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
899 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
900 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
901 p_pic->p[V_PLANE].i_pixel_pitch = 1;
902 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
907 case Pg_VIDEO_FORMAT_UYVY:
908 case Pg_VIDEO_FORMAT_YUY2:
909 if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY)
911 p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
915 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
918 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
919 p_pic->p->i_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 = 4;
922 p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
927 case Pg_VIDEO_FORMAT_RGB555:
928 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
929 p_vout->output.i_rmask = 0x001f;
930 p_vout->output.i_gmask = 0x03e0;
931 p_vout->output.i_bmask = 0x7c00;
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_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
936 p_pic->p->i_pixel_pitch = 2;
937 p_pic->p->i_visible_pitch = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
942 case Pg_VIDEO_FORMAT_RGB565:
943 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
944 p_vout->output.i_rmask = 0x001f;
945 p_vout->output.i_gmask = 0x07e0;
946 p_vout->output.i_bmask = 0xf800;
948 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
949 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
950 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
951 p_pic->p->i_pixel_pitch = 4;
952 p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
957 case Pg_VIDEO_FORMAT_RGB8888:
958 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
959 p_vout->output.i_rmask = 0x000000ff;
960 p_vout->output.i_gmask = 0x0000ff00;
961 p_vout->output.i_bmask = 0x00ff0000;
963 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
964 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
965 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
966 p_pic->p->i_pixel_pitch = 4;
967 p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
974 switch( p_vout->output.i_chroma )
976 #ifdef MODULE_NAME_IS_xvideo
977 case VLC_FOURCC('Y','2','1','1'):
979 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
980 + p_pic->p_sys->p_image->offsets[0];
981 p_pic->p->i_lines = p_vout->output.i_height;
982 /* XXX: this just looks so plain wrong... check it out ! */
983 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
984 p_pic->p->i_pixel_pitch = 4;
985 p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
994 /* This shouldn't happen ! */
1001 /*****************************************************************************
1002 * FreePicture: destroy a picture allocated with NewPicture
1003 *****************************************************************************
1004 * Destroy XImage AND associated data. If using Shm, detach shared memory
1005 * segment from server and process, then free it. The XDestroyImage manpage
1006 * says that both the image structure _and_ the data pointed to by the
1007 * image structure are freed, so no need to free p_image->data.
1008 *****************************************************************************/
1009 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1011 if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
1012 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) &&
1013 p_pic->p_sys->p_image )
1015 PhReleaseImage( p_pic->p_sys->p_image );
1016 free( p_pic->p_sys->p_image );
1018 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
1019 p_pic->p_sys->p_ctx[0] )
1021 PhDCRelease( p_pic->p_sys->p_ctx[0] );
1024 free( p_pic->p_sys );
1028 static int ResizeOverlayOutput(vout_thread_t *p_vout)
1030 int i_width, i_height, i_x, i_y;
1032 PgScalerProps_t props;
1034 props.size = sizeof( props );
1035 props.format = p_vout->p_sys->i_vc_format;
1036 props.flags = Pg_SCALER_PROP_SCALER_ENABLE |
1037 Pg_SCALER_PROP_DOUBLE_BUFFER;
1039 /* enable chroma keying if available */
1040 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
1042 props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
1045 /* set viewport position */
1046 props.viewport.ul.x = p_vout->p_sys->pos.x;
1047 props.viewport.ul.y = p_vout->p_sys->pos.y;
1048 if( !p_vout->b_fullscreen )
1050 props.viewport.ul.x += p_vout->p_sys->frame.ul.x;
1051 props.viewport.ul.y += p_vout->p_sys->frame.ul.y;
1054 /* set viewport dimension */
1055 vout_PlacePicture( p_vout, p_vout->p_sys->dim.w,
1056 p_vout->p_sys->dim.h,
1057 &i_x, &i_y, &i_width, &i_height );
1059 props.viewport.ul.x += i_x;
1060 props.viewport.ul.y += i_y;
1061 props.viewport.lr.x = i_width + props.viewport.ul.x;
1062 props.viewport.lr.y = i_height + props.viewport.ul.y;
1064 /* set source dimension */
1065 props.src_dim.w = p_vout->output.i_width;
1066 props.src_dim.h = p_vout->output.i_height;
1068 /* configure scaler channel */
1069 i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props );
1073 msg_Err( p_vout, "unable to configure video channel" );
1081 /*****************************************************************************
1082 * SetPalette: sets an 8 bpp palette
1083 *****************************************************************************
1084 * This function sets the palette given as an argument. It does not return
1085 * anything, but could later send information on which colors it was unable
1087 *****************************************************************************/
1088 static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue )
1092 /* allocate palette */
1093 for( i = 0; i < 255; i++ )
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 );