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>
36 #include <videolan/vlc.h>
39 #include "video_output.h"
41 #include "interface.h"
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
53 #define MODE_NORMAL_MEM 0
54 #define MODE_SHARED_MEM 1
55 #define MODE_VIDEO_MEM 2
56 #define MODE_VIDEO_OVERLAY 3
58 typedef struct vout_sys_s
64 PtWidget_t * p_window;
66 /* Color palette for 8bpp */
67 PgColor_t p_colors[255];
69 /* [shared] memory blit */
72 /* video memory blit */
75 PgVideoChannel_t * p_channel;
80 int i_bytes_per_pixel;
83 /* position & dimensions */
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 typedef struct picture_sys_s
101 /* [shared] memory blit */
104 /* video memory blit and video overlay */
105 PdOffscreenContext_t * p_ctx[3]; /* 0: y, 1: u, 2: v */
111 /*****************************************************************************
113 *****************************************************************************/
114 static int vout_Create ( struct vout_thread_s * );
115 static int vout_Init ( struct vout_thread_s * );
116 static void vout_End ( struct vout_thread_s * );
117 static void vout_Destroy ( struct vout_thread_s * );
118 static int vout_Manage ( struct vout_thread_s * );
119 static void vout_Render ( vout_thread_t *, picture_t * );
120 static void vout_Display ( vout_thread_t *, picture_t * );
122 static int QNXInitDisplay ( struct vout_thread_s * );
123 static int QNXCreateWnd ( struct vout_thread_s * );
124 static int QNXDestroyWnd ( struct vout_thread_s * );
126 static int NewPicture ( vout_thread_t *, picture_t *, int );
127 static void FreePicture ( vout_thread_t *, picture_t * );
128 static int ResizeOverlayOutput ( vout_thread_t * );
129 static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * );
131 /*****************************************************************************
132 * Functions exported as capabilities. They are declared as static so that
133 * we don't pollute the namespace too much.
134 *****************************************************************************/
135 void _M( vout_getfunctions )( function_list_t * p_function_list )
137 p_function_list->functions.vout.pf_create = vout_Create;
138 p_function_list->functions.vout.pf_init = vout_Init;
139 p_function_list->functions.vout.pf_end = vout_End;
140 p_function_list->functions.vout.pf_destroy = vout_Destroy;
141 p_function_list->functions.vout.pf_manage = vout_Manage;
142 p_function_list->functions.vout.pf_render = vout_Render;
143 p_function_list->functions.vout.pf_display = vout_Display;
146 /*****************************************************************************
147 * vout_Create: allocate QNX video thread output method
148 *****************************************************************************
149 * This function allocate and initialize a QNX vout method. It uses some of the
150 * vout properties to choose the window size, and change them according to the
151 * actual properties of the display.
152 *****************************************************************************/
153 static int vout_Create( vout_thread_t *p_vout )
155 /* init connection to photon */
156 if( PtInit( "/dev/photon" ) != 0 )
158 intf_ErrMsg( "vout error: unable to connect to photon" );
162 /* allocate structure */
163 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
164 if( p_vout->p_sys == NULL )
166 intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
170 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
172 p_vout->b_fullscreen =
173 config_GetIntVariable( "fullscreen" );
174 p_vout->p_sys->i_mode =
175 config_GetIntVariable( "nooverlay" ) ?
176 MODE_NORMAL_MEM : MODE_VIDEO_OVERLAY;
177 p_vout->p_sys->dim.w = p_vout->i_window_width;
178 p_vout->p_sys->dim.h = p_vout->i_window_height;
180 /* init display and create window */
181 if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
183 free( p_vout->p_sys );
190 /*****************************************************************************
191 * vout_Init: initialize QNX video thread output method
192 *****************************************************************************
193 * This function create the buffers needed by the output thread. It is called
194 * at the beginning of the thread, but also each time the window is resized.
195 *****************************************************************************/
196 static int vout_Init( vout_thread_t *p_vout )
201 I_OUTPUTPICTURES = 0;
203 switch( p_vout->p_sys->i_mode )
205 case MODE_NORMAL_MEM:
206 case MODE_SHARED_MEM:
207 p_vout->output.i_width = p_vout->p_sys->dim.w;
208 p_vout->output.i_height = p_vout->p_sys->dim.h;
210 /* Assume we have square pixels */
211 p_vout->output.i_aspect = p_vout->p_sys->dim.w
212 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
216 p_vout->output.i_width = p_vout->p_sys->dim.w;
217 p_vout->output.i_height = p_vout->p_sys->dim.h;
219 /* Assume we have square pixels */
220 p_vout->output.i_aspect = p_vout->p_sys->dim.w
221 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
224 case MODE_VIDEO_OVERLAY:
225 p_vout->output.i_width = p_vout->render.i_width;
226 p_vout->output.i_height = p_vout->render.i_height;
227 p_vout->output.i_aspect = p_vout->render.i_aspect;
229 if (ResizeOverlayOutput(p_vout))
236 /* This shouldn't happen ! */
240 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
241 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
245 /* Find an empty picture slot */
246 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
248 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
250 p_pic = p_vout->p_picture + i_index;
255 /* Allocate the picture */
256 if( p_pic == NULL || NewPicture( p_vout, p_pic, I_OUTPUTPICTURES ) )
261 p_pic->i_status = DESTROYED_PICTURE;
262 p_pic->i_type = DIRECT_PICTURE;
264 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
272 /*****************************************************************************
273 * vout_End: terminate QNX video thread output method
274 *****************************************************************************
275 * Destroy the buffers created by vout_Init. It is called at the end of
276 * the thread, but also each time the window is resized.
277 *****************************************************************************/
278 static void vout_End( vout_thread_t *p_vout )
282 /* Free the direct buffers we allocated */
283 for( i_index = I_OUTPUTPICTURES ; i_index ; )
286 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
290 /*****************************************************************************
291 * vout_Destroy: destroy QNX video thread output method
292 *****************************************************************************
293 * Terminate an output method created by vout_CreateOutputMethod
294 *****************************************************************************/
295 static void vout_Destroy( vout_thread_t *p_vout )
297 /* destroy the window */
298 QNXDestroyWnd( p_vout );
300 /* destroy structure */
301 free( p_vout->p_sys );
304 /*****************************************************************************
305 * vout_Manage: handle QNX events
306 *****************************************************************************
307 * This function should be called regularly by video output thread. It allows
308 * window resizing. It returns a non null value on error.
309 *****************************************************************************/
310 static int vout_Manage( vout_thread_t *p_vout )
314 boolean_t b_repos = 0;
316 if (p_vout->b_die == 1)
321 /* allocate buffer for event */
322 i_buflen = sizeof( PhEvent_t ) * 4;
323 if( ( p_event = malloc( i_buflen ) ) == NULL )
325 intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
332 memset( p_event, 0, i_buflen );
333 i_ev = PhEventPeek( p_event, i_buflen );
335 if( i_ev == Ph_RESIZE_MSG )
337 i_buflen = PhGetMsgSize( p_event );
338 if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
340 intf_ErrMsg( "vout error: %s", strerror( ENOMEM ) );
344 else if( i_ev == Ph_EVENT_MSG )
346 PtEventHandler( p_event );
348 if( p_event->type == Ph_EV_WM )
350 PhWindowEvent_t *p_ev = PhGetData( p_event );
352 switch( p_ev->event_f )
355 p_main->p_intf->b_die = 1;
359 p_vout->p_sys->pos.x = p_ev->pos.x;
360 p_vout->p_sys->pos.y = p_ev->pos.y;
365 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
366 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
367 p_vout->p_sys->dim.w = p_ev->size.w;
368 p_vout->p_sys->dim.h = p_ev->size.h;
369 p_vout->i_changes |= VOUT_SIZE_CHANGE;
373 else if( p_event->type == Ph_EV_KEY )
375 PhKeyEvent_t *p_ev = PhGetData( p_event );
376 long i_key = p_ev->key_sym;
378 if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
379 ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
385 p_main->p_intf->b_die = 1;
390 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
395 p_vout->b_grayscale = ! p_vout->b_grayscale;
396 p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
400 if( i_key >= Pk_0 && i_key <= Pk_9 )
402 // network_ChannelJoin( i_key );
409 } while( i_ev != -1 && i_ev != 0 );
416 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
420 p_vout->b_fullscreen = !p_vout->b_fullscreen;
421 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
423 if( p_vout->b_fullscreen )
425 p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x;
426 p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y;
427 p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0;
428 dim.w = p_vout->p_sys->screen_dim.w + 1;
429 dim.h = p_vout->p_sys->screen_dim.h + 1;
433 p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x;
434 p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y;
435 dim.w = p_vout->p_sys->old_dim.w + 1;
436 dim.h = p_vout->p_sys->old_dim.h + 1;
439 /* modify render flags, border */
440 PtSetResource( p_vout->p_sys->p_window,
441 Pt_ARG_WINDOW_RENDER_FLAGS,
442 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
443 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
445 /* set position and dimension */
446 PtSetResource( p_vout->p_sys->p_window,
447 Pt_ARG_POS, &p_vout->p_sys->pos, 0 );
448 PtSetResource( p_vout->p_sys->p_window,
449 Pt_ARG_DIM, &dim, 0 );
451 /* mark as damaged to force redraw */
452 PtDamageWidget( p_vout->p_sys->p_window );
458 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
460 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
462 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
464 ResizeOverlayOutput(p_vout);
469 p_vout->output.i_width = p_vout->p_sys->dim.w;
470 p_vout->output.i_height = p_vout->p_sys->dim.h;
471 p_vout->i_changes |= VOUT_YUV_CHANGE;
474 if( vout_Init( p_vout ) )
476 intf_ErrMsg( "vout error: cannot resize display" );
482 intf_Msg( "vout: video display resized (%dx%d)",
483 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h );
487 * position change, move video channel
489 if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
491 ResizeOverlayOutput(p_vout);
494 return( i_ev == -1 );
497 /*****************************************************************************
498 * vout_Render: render previously calculated output
499 *****************************************************************************/
500 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
505 /*****************************************************************************
506 * vout_Display: displays previously rendered output
507 *****************************************************************************
508 * This function send the currently rendered image to QNX server, wait until
509 * it is displayed and switch the two rendering buffer, preparing next frame.
510 *****************************************************************************/
511 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
513 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
514 p_vout->p_sys->i_mode == MODE_SHARED_MEM )
516 PhPoint_t pos = { 0, 0 };
518 PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
519 if (p_vout->p_sys->i_screen_depth == 8)
521 PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0);
523 PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 );
526 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
528 PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } };
530 // PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
531 PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc );
536 /*****************************************************************************
537 * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
538 *****************************************************************************/
539 static int QNXInitDisplay( p_vout_thread_t p_vout )
542 PgDisplaySettings_t cfg;
543 PgVideoModeInfo_t minfo;
545 /* get graphics card hw capabilities */
546 if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
548 intf_ErrMsg( "vout error: unable to get gfx card capabilities" );
552 /* get current video mode */
553 if( PgGetVideoMode( &cfg ) != 0 )
555 intf_ErrMsg( "vout error: unable to get current video mode" );
559 /* get video mode info */
560 if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
562 intf_ErrMsg( "vout error: unable to get info for video mode" );
566 /* switch to normal mode if no overlay support */
567 // printf("minfo.mode_capabilities1: 0x%x\n", minfo.mode_capabilities1);
569 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY &&
570 !( minfo.mode_capabilities1 & PgVM_MODE_CAP1_VIDEO_OVERLAY ) )
572 intf_ErrMsg( "vout error: no overlay support detected" );
573 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
576 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
579 PgScalerCaps_t vcaps;
581 if( ( p_vout->p_sys->p_channel =
582 PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
584 intf_ErrMsg( "vout error: unable to create video channel" );
585 printf("errno = %d\n", errno);
586 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
590 vcaps.size = sizeof( vcaps );
591 while( PgGetScalerCapabilities( p_vout->p_sys->p_channel,
594 printf("vcaps.format = 0x%x\n", vcaps.format);
595 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
596 vcaps.format == Pg_VIDEO_FORMAT_YUV420 ||
597 vcaps.format == Pg_VIDEO_FORMAT_YUY2 ||
598 vcaps.format == Pg_VIDEO_FORMAT_UYVY ||
599 vcaps.format == Pg_VIDEO_FORMAT_RGB555 ||
600 vcaps.format == Pg_VIDEO_FORMAT_RGB565 ||
601 vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
603 p_vout->p_sys->i_vc_flags = vcaps.flags;
604 p_vout->p_sys->i_vc_format = vcaps.format;
607 vcaps.size = sizeof( vcaps );
610 if( p_vout->p_sys->i_vc_format == 0 )
612 intf_ErrMsg( "vout error: need YV12, YUY2 or RGB8888 overlay" );
614 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
619 /* use video ram if we have enough available */
620 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
621 (minfo.bits_per_pixel != 8) &&
622 hwcaps.currently_available_video_ram >=
623 ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) )
625 p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
626 printf("Using video memory...\n");
629 p_vout->p_sys->i_img_type = minfo.type;
630 p_vout->p_sys->screen_dim.w = minfo.width;
631 p_vout->p_sys->screen_dim.h = minfo.height;
632 p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel;
634 switch( p_vout->p_sys->i_screen_depth )
637 p_vout->output.i_chroma = FOURCC_RGB2;
638 p_vout->p_sys->i_bytes_per_pixel = 1;
639 p_vout->output.pf_setpalette = SetPalette;
643 p_vout->output.i_chroma = FOURCC_RV15;
644 p_vout->p_sys->i_bytes_per_pixel = 2;
645 p_vout->output.i_rmask = 0x7c00;
646 p_vout->output.i_gmask = 0x03e0;
647 p_vout->output.i_bmask = 0x001f;
651 p_vout->output.i_chroma = FOURCC_RV16;
652 p_vout->p_sys->i_bytes_per_pixel = 2;
653 p_vout->output.i_rmask = 0xf800;
654 p_vout->output.i_gmask = 0x07e0;
655 p_vout->output.i_bmask = 0x001f;
659 p_vout->output.i_chroma = FOURCC_RV24;
660 p_vout->p_sys->i_bytes_per_pixel = 3;
661 p_vout->output.i_rmask = 0xff0000;
662 p_vout->output.i_gmask = 0x00ff00;
663 p_vout->output.i_bmask = 0x0000ff;
668 p_vout->output.i_chroma = FOURCC_RV32;
669 p_vout->p_sys->i_bytes_per_pixel = 4;
670 p_vout->output.i_rmask = 0xff0000;
671 p_vout->output.i_gmask = 0x00ff00;
672 p_vout->output.i_bmask = 0x0000ff;
679 /*****************************************************************************
680 * QNXCreateWnd: create and realize the main window
681 *****************************************************************************/
682 static int QNXCreateWnd( p_vout_thread_t p_vout )
685 PhPoint_t pos = { 0, 0 };
686 PgColor_t color = Pg_BLACK;
688 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
690 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
692 color = PgGetOverlayChromaColor();
696 /* fullscreen, set dimension */
697 if( p_vout->b_fullscreen )
699 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
700 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
701 p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
702 p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
705 /* set window parameters */
706 PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
707 PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
708 PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
709 PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VideoLan Client", 0 );
710 PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
711 PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
712 Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
713 PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
714 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
715 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
718 p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
719 if( p_vout->p_sys->p_window == NULL )
721 intf_ErrMsg( "vout error: unable to create window" );
725 /* realize the window widget */
726 if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
728 intf_ErrMsg( "vout error: unable to realize window widget" );
729 PtDestroyWidget( p_vout->p_sys->p_window );
733 /* get window frame size */
734 if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window,
735 &p_vout->p_sys->frame ) != 0 )
737 intf_ErrMsg( "vout error: unable to get window frame size" );
738 PtDestroyWidget( p_vout->p_sys->p_window );
745 /*****************************************************************************
746 * QNXDestroyWnd: unrealize and destroy the main window
747 *****************************************************************************/
748 static int QNXDestroyWnd( p_vout_thread_t p_vout )
750 /* destroy the window widget */
751 PtUnrealizeWidget( p_vout->p_sys->p_window );
752 // PtDestroyWidget( p_vout->p_sys->p_window );
754 /* destroy video channel */
755 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
757 PgDestroyVideoChannel( p_vout->p_sys->p_channel );
764 /*****************************************************************************
765 * NewPicture: allocate a picture
766 *****************************************************************************
767 * Returns 0 on success, -1 otherwise
768 *****************************************************************************/
769 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index )
771 /* We know the chroma, allocate a buffer which will be used
772 * directly by the decoder */
773 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
775 if( p_pic->p_sys == NULL )
780 switch( p_vout->p_sys->i_mode )
782 case MODE_NORMAL_MEM:
783 case MODE_SHARED_MEM:
784 /* create images for [shared] memory blit */
785 if( !( p_pic->p_sys->p_image = PhCreateImage( NULL,
786 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
787 p_vout->p_sys->i_img_type, NULL, 0,
788 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
789 intf_ErrMsg( "vout error: cannot create image" );
790 free( p_pic->p_sys );
794 p_pic->p->p_pixels = p_pic->p_sys->p_image->image;
795 p_pic->p->i_lines = p_pic->p_sys->p_image->size.h;
796 p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl;
797 p_pic->p->i_pixel_bytes = p_vout->p_sys->i_bytes_per_pixel;
799 if( p_pic->p->i_pitch == p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_image->size.w )
801 p_pic->p->b_margin = 0;
805 p_pic->p->b_margin = 1;
806 p_pic->p->b_hidden = 1;
807 p_pic->p->i_visible_bytes = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_image->size.w;
814 /* create offscreen contexts for video memory blit */
815 if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
816 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
817 Pg_OSC_MEM_PAGE_ALIGN) ) == NULL )
819 intf_ErrMsg( "vout error: unable to create offscreen context" );
820 free( p_pic->p_sys );
824 /* get context pointers */
825 if( ( p_pic->p_sys->p_buf[0] =
826 PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL )
828 intf_ErrMsg( "vout error: unable to get offscreen context ptr" );
829 PhDCRelease ( p_pic->p_sys->p_ctx[0] );
830 p_pic->p_sys->p_ctx[0] = NULL;
831 free( p_pic->p_sys );
835 p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch;
836 memset( p_pic->p_sys->p_buf[0], 0,
837 p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h );
839 p_pic->p->p_pixels = p_pic->p_sys->p_buf[0];
840 p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h;
841 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch;
842 p_pic->p->i_pixel_bytes = p_vout->p_sys->i_bytes_per_pixel;
844 if( p_pic->p->i_pitch == p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_ctx[0]->dim.w )
846 p_pic->p->b_margin = 0;
850 p_pic->p->b_margin = 1;
851 p_pic->p->b_hidden = 1;
852 p_pic->p->i_visible_bytes = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_ctx[0]->dim.w;
858 case MODE_VIDEO_OVERLAY:
861 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1;
862 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1;
863 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1;
867 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2;
868 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2;
869 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2;
872 p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] );
873 if( p_pic->p_sys->p_buf[Y_PLANE] == NULL )
875 intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
879 switch (p_vout->p_sys->i_vc_format)
881 case Pg_VIDEO_FORMAT_YUV420:
882 p_vout->output.i_chroma = FOURCC_I420;
884 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
885 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
887 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
888 p_pic->p_sys->p_buf[V_PLANE] == NULL )
890 intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
894 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
895 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
896 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
897 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
898 p_pic->p[Y_PLANE].b_margin = 0;
900 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
901 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
902 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
903 p_pic->p[U_PLANE].i_pixel_bytes = 1;
904 p_pic->p[U_PLANE].b_margin = 0;
906 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
907 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
908 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
909 p_pic->p[V_PLANE].i_pixel_bytes = 1;
910 p_pic->p[V_PLANE].b_margin = 0;
915 case Pg_VIDEO_FORMAT_YV12:
916 p_vout->output.i_chroma = FOURCC_YV12;
918 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
919 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
921 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
922 p_pic->p_sys->p_buf[V_PLANE] == NULL )
924 intf_ErrMsg( "vout error: unable to get video channel ctx ptr" );
928 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
929 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
930 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
931 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
932 p_pic->p[Y_PLANE].b_margin = 0;
934 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
935 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
936 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
937 p_pic->p[U_PLANE].i_pixel_bytes = 1;
938 p_pic->p[U_PLANE].b_margin = 0;
940 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
941 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
942 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
943 p_pic->p[V_PLANE].i_pixel_bytes = 1;
944 p_pic->p[V_PLANE].b_margin = 0;
949 case Pg_VIDEO_FORMAT_UYVY:
950 case Pg_VIDEO_FORMAT_YUY2:
951 if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY)
953 p_vout->output.i_chroma = FOURCC_UYVY;
957 p_vout->output.i_chroma = FOURCC_YUY2;
960 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
961 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
962 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
963 p_pic->p->i_pixel_bytes = 4;
964 p_pic->p->b_margin = 0;
969 case Pg_VIDEO_FORMAT_RGB555:
970 p_vout->output.i_chroma = FOURCC_RV15;
971 p_vout->output.i_rmask = 0x001f;
972 p_vout->output.i_gmask = 0x03e0;
973 p_vout->output.i_bmask = 0x7c00;
975 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
976 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
977 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
978 p_pic->p->i_pixel_bytes = 2;
980 if( p_pic->p->i_pitch == 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
982 p_pic->p->b_margin = 0;
986 p_pic->p->b_margin = 1;
987 p_pic->p->b_hidden = 1;
988 p_pic->p->i_visible_bytes = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
994 case Pg_VIDEO_FORMAT_RGB565:
995 p_vout->output.i_chroma = FOURCC_RV16;
996 p_vout->output.i_rmask = 0x001f;
997 p_vout->output.i_gmask = 0x07e0;
998 p_vout->output.i_bmask = 0xf800;
1000 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
1001 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
1002 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
1003 p_pic->p->i_pixel_bytes = 4;
1005 if( p_pic->p->i_pitch == 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
1007 p_pic->p->b_margin = 0;
1011 p_pic->p->b_margin = 1;
1012 p_pic->p->b_hidden = 1;
1013 p_pic->p->i_visible_bytes = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
1016 p_pic->i_planes = 1;
1019 case Pg_VIDEO_FORMAT_RGB8888:
1020 p_vout->output.i_chroma = FOURCC_RV32;
1021 p_vout->output.i_rmask = 0x000000ff;
1022 p_vout->output.i_gmask = 0x0000ff00;
1023 p_vout->output.i_bmask = 0x00ff0000;
1025 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
1026 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
1027 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
1028 p_pic->p->i_pixel_bytes = 4;
1030 if( p_pic->p->i_pitch == 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w )
1032 p_pic->p->b_margin = 0;
1036 p_pic->p->b_margin = 1;
1037 p_pic->p->b_hidden = 1;
1038 p_pic->p->i_visible_bytes = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
1041 p_pic->i_planes = 1;
1046 switch( p_vout->output.i_chroma )
1048 #ifdef MODULE_NAME_IS_xvideo
1051 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1052 + p_pic->p_sys->p_image->offsets[0];
1053 p_pic->p->i_lines = p_vout->output.i_height;
1054 /* XXX: this just looks so plain wrong... check it out ! */
1055 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
1056 p_pic->p->i_pixel_bytes = 4;
1057 p_pic->p->b_margin = 0;
1059 p_pic->i_planes = 1;
1066 /* This shouldn't happen ! */
1073 /*****************************************************************************
1074 * FreePicture: destroy a picture allocated with NewPicture
1075 *****************************************************************************
1076 * Destroy XImage AND associated data. If using Shm, detach shared memory
1077 * segment from server and process, then free it. The XDestroyImage manpage
1078 * says that both the image structure _and_ the data pointed to by the
1079 * image structure are freed, so no need to free p_image->data.
1080 *****************************************************************************/
1081 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1083 if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
1084 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) &&
1085 p_pic->p_sys->p_image )
1087 PhReleaseImage( p_pic->p_sys->p_image );
1088 free( p_pic->p_sys->p_image );
1090 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
1091 p_pic->p_sys->p_ctx[0] )
1093 PhDCRelease( p_pic->p_sys->p_ctx[0] );
1096 free( p_pic->p_sys );
1100 static int ResizeOverlayOutput(vout_thread_t *p_vout)
1102 int i_width, i_height, i_x, i_y;
1104 PgScalerProps_t props;
1106 props.size = sizeof( props );
1107 props.format = p_vout->p_sys->i_vc_format;
1108 props.flags = Pg_SCALER_PROP_SCALER_ENABLE |
1109 Pg_SCALER_PROP_DOUBLE_BUFFER;
1111 /* enable chroma keying if available */
1112 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
1114 props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
1117 /* set viewport position */
1118 props.viewport.ul.x = p_vout->p_sys->pos.x;
1119 props.viewport.ul.y = p_vout->p_sys->pos.y;
1120 if( !p_vout->b_fullscreen )
1122 props.viewport.ul.x += p_vout->p_sys->frame.ul.x;
1123 props.viewport.ul.y += p_vout->p_sys->frame.ul.y;
1126 /* set viewport dimension */
1127 vout_PlacePicture( p_vout, p_vout->p_sys->dim.w,
1128 p_vout->p_sys->dim.h,
1129 &i_x, &i_y, &i_width, &i_height );
1131 props.viewport.ul.x += i_x;
1132 props.viewport.ul.y += i_y;
1133 props.viewport.lr.x = i_width + props.viewport.ul.x;
1134 props.viewport.lr.y = i_height + props.viewport.ul.y;
1136 /* set source dimension */
1137 props.src_dim.w = p_vout->output.i_width;
1138 props.src_dim.h = p_vout->output.i_height;
1140 /* configure scaler channel */
1141 i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props );
1145 intf_ErrMsg( "vout error: unable to configure video channel" );
1153 /*****************************************************************************
1154 * SetPalette: sets an 8 bpp palette
1155 *****************************************************************************
1156 * This function sets the palette given as an argument. It does not return
1157 * anything, but could later send information on which colors it was unable
1159 *****************************************************************************/
1160 static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue )
1164 /* allocate palette */
1165 for( i = 0; i < 255; i++ )
1167 /* kludge: colors are indexed reversely because color 255 seems
1168 * to be reserved for black even if we try to set it to white */
1169 p_vout->p_sys->p_colors[ i ] = PgRGB( red[ i ] >> 8, green[ i ] >> 8, blue[ i ] >> 8 );