1 /*****************************************************************************
2 * vout.c: QNX RTOS video output display method
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <errno.h> /* ENOMEM */
29 #include <photon/PtWidget.h>
30 #include <photon/PtWindow.h>
31 #include <photon/PtLabel.h>
32 #include <photon/PdDirect.h>
35 #include <vlc_interface.h>
38 /*****************************************************************************
39 * vout_sys_t: video output QNX method descriptor
40 *****************************************************************************
41 * This structure is part of the video output thread descriptor.
42 * It describes the QNX specific properties of an output thread. QNX video
43 * output is performed through regular resizable windows. Windows can be
44 * dynamically resized to adapt to the size of the streams.
45 *****************************************************************************/
46 #define MAX_DIRECTBUFFERS 2
48 #define MODE_NORMAL_MEM 0
49 #define MODE_SHARED_MEM 1
50 #define MODE_VIDEO_MEM 2
51 #define MODE_VIDEO_OVERLAY 3
59 PtWidget_t * p_window;
61 /* Color palette for 8bpp */
62 PgColor_t p_colors[255];
64 /* [shared] memory blit */
67 /* video memory blit */
70 PgVideoChannel_t * p_channel;
75 int i_bytes_per_pixel;
78 /* position & dimensions */
88 /*****************************************************************************
89 * picture_sys_t: direct buffer method descriptor
90 *****************************************************************************
91 * This structure is part of the picture descriptor, it describes the
92 * XVideo specific properties of a direct buffer.
93 *****************************************************************************/
96 /* [shared] memory blit */
99 /* video memory blit and video overlay */
100 PdOffscreenContext_t * p_ctx[3]; /* 0: y, 1: u, 2: v */
105 /*****************************************************************************
107 *****************************************************************************/
108 static int QNXInit ( vout_thread_t * );
109 static void QNXEnd ( vout_thread_t * );
110 static int QNXManage ( vout_thread_t * );
111 static void QNXDisplay ( vout_thread_t *, picture_t * );
113 static int QNXInitDisplay ( vout_thread_t * );
114 static int QNXCreateWnd ( vout_thread_t * );
115 static int QNXDestroyWnd ( vout_thread_t * );
117 static int NewPicture ( vout_thread_t *, picture_t *, int );
118 static void FreePicture ( vout_thread_t *, picture_t * );
119 static int ResizeOverlayOutput ( vout_thread_t * );
120 static void SetPalette ( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
122 /*****************************************************************************
123 * OpenVideo: allocate QNX video thread output method
124 *****************************************************************************
125 * This function allocate and initialize a QNX vout method. It uses some of the
126 * vout properties to choose the window size, and change them according to the
127 * actual properties of the display.
128 *****************************************************************************/
129 int E_(OpenVideo) ( vlc_object_t *p_this )
131 vout_thread_t * p_vout = (vout_thread_t *)p_this;
133 /* init connection to photon */
134 if( PtInit( "/dev/photon" ) != 0 )
136 msg_Err( p_vout, "unable to connect to photon" );
140 /* allocate structure */
141 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
142 if( p_vout->p_sys == NULL )
144 msg_Err( p_vout, "out of memory" );
148 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
150 p_vout->b_fullscreen = config_GetInt( p_vout, "fullscreen" );
151 p_vout->p_sys->i_mode = config_GetInt( p_vout, "overlay" ) ?
152 MODE_VIDEO_OVERLAY : MODE_VIDEO_MEM;
153 p_vout->p_sys->dim.w = p_vout->i_window_width;
154 p_vout->p_sys->dim.h = p_vout->i_window_height;
156 /* init display and create window */
157 if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
159 free( p_vout->p_sys );
163 p_vout->pf_init = QNXInit;
164 p_vout->pf_end = QNXEnd;
165 p_vout->pf_manage = QNXManage;
166 p_vout->pf_render = NULL;
167 p_vout->pf_display = QNXDisplay;
172 /*****************************************************************************
173 * QNXInit: initialize QNX video thread output method
174 *****************************************************************************
175 * This function create the buffers needed by the output thread. It is called
176 * at the beginning of the thread, but also each time the window is resized.
177 *****************************************************************************/
178 static int QNXInit( vout_thread_t *p_vout )
183 I_OUTPUTPICTURES = 0;
185 switch( p_vout->p_sys->i_mode )
187 case MODE_NORMAL_MEM:
188 case MODE_SHARED_MEM:
189 p_vout->output.i_width = p_vout->p_sys->dim.w;
190 p_vout->output.i_height = p_vout->p_sys->dim.h;
192 /* Assume we have square pixels */
193 p_vout->output.i_aspect = p_vout->p_sys->dim.w
194 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
198 p_vout->output.i_width = p_vout->p_sys->dim.w;
199 p_vout->output.i_height = p_vout->p_sys->dim.h;
201 /* Assume we have square pixels */
202 p_vout->output.i_aspect = p_vout->p_sys->dim.w
203 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
206 case MODE_VIDEO_OVERLAY:
207 p_vout->output.i_width = p_vout->render.i_width;
208 p_vout->output.i_height = p_vout->render.i_height;
209 p_vout->output.i_aspect = p_vout->render.i_aspect;
211 if (ResizeOverlayOutput(p_vout))
218 /* This shouldn't happen ! */
222 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
223 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
227 /* Find an empty picture slot */
228 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
230 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
232 p_pic = p_vout->p_picture + i_index;
237 /* Allocate the picture */
238 if( p_pic == NULL || NewPicture( p_vout, p_pic, I_OUTPUTPICTURES ) )
243 p_pic->i_status = DESTROYED_PICTURE;
244 p_pic->i_type = DIRECT_PICTURE;
246 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
254 /*****************************************************************************
255 * QNXEnd: terminate QNX video thread output method
256 *****************************************************************************
257 * Destroy the buffers created by QNXInit. It is called at the end of
258 * the thread, but also each time the window is resized.
259 *****************************************************************************/
260 static void QNXEnd( vout_thread_t *p_vout )
264 /* Free the direct buffers we allocated */
265 for( i_index = I_OUTPUTPICTURES ; i_index ; )
268 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
272 /*****************************************************************************
273 * CloseVideo: destroy QNX video thread output method
274 *****************************************************************************
275 * Terminate an output method created by QNXCreate
276 *****************************************************************************/
277 void E_(CloseVideo) ( vlc_object_t *p_this )
279 vout_thread_t * p_vout = (vout_thread_t *)p_this;
281 /* destroy the window */
282 QNXDestroyWnd( p_vout );
284 /* destroy structure */
285 free( p_vout->p_sys );
288 /*****************************************************************************
289 * QNXManage: handle QNX events
290 *****************************************************************************
291 * This function should be called regularly by video output thread. It allows
292 * window resizing. It returns a non null value on error.
293 *****************************************************************************/
294 static int QNXManage( vout_thread_t *p_vout )
298 vlc_bool_t b_repos = 0;
305 /* allocate buffer for event */
306 i_buflen = sizeof( PhEvent_t ) * 4;
307 if( ( p_event = malloc( i_buflen ) ) == NULL )
309 msg_Err( p_vout, "out of memory" );
316 memset( p_event, 0, i_buflen );
317 i_ev = PhEventPeek( p_event, i_buflen );
319 if( i_ev == Ph_RESIZE_MSG )
321 i_buflen = PhGetMsgSize( p_event );
322 if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
324 msg_Err( p_vout, "out of memory" );
328 else if( i_ev == Ph_EVENT_MSG )
330 PtEventHandler( p_event );
332 if( p_event->type == Ph_EV_WM )
334 PhWindowEvent_t *p_ev = PhGetData( p_event );
336 switch( p_ev->event_f )
339 p_vout->p_libvlc->b_die = VLC_TRUE;
343 p_vout->p_sys->pos.x = p_ev->pos.x;
344 p_vout->p_sys->pos.y = p_ev->pos.y;
349 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
350 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
351 p_vout->p_sys->dim.w = p_ev->size.w;
352 p_vout->p_sys->dim.h = p_ev->size.h;
353 p_vout->i_changes |= VOUT_SIZE_CHANGE;
357 else if( p_event->type == Ph_EV_KEY )
359 PhKeyEvent_t *p_ev = PhGetData( p_event );
360 long i_key = p_ev->key_sym;
362 if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
363 ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
369 p_vout->p_libvlc->b_die = VLC_TRUE;
374 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
379 p_vout->b_grayscale = ! p_vout->b_grayscale;
380 p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE;
389 } while( i_ev != -1 && i_ev != 0 );
396 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
400 p_vout->b_fullscreen = !p_vout->b_fullscreen;
401 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
403 if( p_vout->b_fullscreen )
405 p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x;
406 p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y;
407 p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0;
408 dim.w = p_vout->p_sys->screen_dim.w + 1;
409 dim.h = p_vout->p_sys->screen_dim.h + 1;
413 p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x;
414 p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y;
415 dim.w = p_vout->p_sys->old_dim.w + 1;
416 dim.h = p_vout->p_sys->old_dim.h + 1;
419 /* modify render flags, border */
420 PtSetResource( p_vout->p_sys->p_window,
421 Pt_ARG_WINDOW_RENDER_FLAGS,
422 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
423 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
425 /* set position and dimension */
426 PtSetResource( p_vout->p_sys->p_window,
427 Pt_ARG_POS, &p_vout->p_sys->pos, 0 );
428 PtSetResource( p_vout->p_sys->p_window,
429 Pt_ARG_DIM, &dim, 0 );
431 /* mark as damaged to force redraw */
432 PtDamageWidget( p_vout->p_sys->p_window );
438 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
440 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
442 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
444 ResizeOverlayOutput(p_vout);
449 p_vout->output.i_width = p_vout->p_sys->dim.w;
450 p_vout->output.i_height = p_vout->p_sys->dim.h;
451 p_vout->i_changes |= VOUT_YUV_CHANGE;
454 if( QNXInit( p_vout ) )
456 msg_Err( p_vout, "cannot resize display" );
462 msg_Dbg( p_vout, "video display resized (%dx%d)",
463 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h );
467 * position change, move video channel
469 if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
471 ResizeOverlayOutput(p_vout);
474 return( i_ev == -1 );
477 /*****************************************************************************
478 * QNXDisplay: displays previously rendered output
479 *****************************************************************************
480 * This function send the currently rendered image to QNX server, wait until
481 * it is displayed and switch the two rendering buffer, preparing next frame.
482 *****************************************************************************/
483 static void QNXDisplay( vout_thread_t *p_vout, picture_t *p_pic )
485 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
486 p_vout->p_sys->i_mode == MODE_SHARED_MEM )
488 PhPoint_t pos = { 0, 0 };
490 PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
491 if (p_vout->p_sys->i_screen_depth == 8)
493 PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0);
495 PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 );
498 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
500 PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } };
502 // PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
503 PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc );
508 /*****************************************************************************
509 * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
510 *****************************************************************************/
511 static int QNXInitDisplay( vout_thread_t * p_vout )
514 PgDisplaySettings_t cfg;
515 PgVideoModeInfo_t minfo;
517 /* get graphics card hw capabilities */
518 if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
520 msg_Err( p_vout, "unable to get gfx card capabilities" );
524 /* get current video mode */
525 if( PgGetVideoMode( &cfg ) != 0 )
527 msg_Err( p_vout, "unable to get current video mode" );
531 /* get video mode info */
532 if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
534 msg_Err( p_vout, "unable to get info for video mode" );
538 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
541 PgScalerCaps_t vcaps;
543 if( ( p_vout->p_sys->p_channel =
544 PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
546 msg_Err( p_vout, "unable to create video channel" );
547 printf("errno = %d\n", errno);
548 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
552 vcaps.size = sizeof( vcaps );
553 while( PgGetScalerCapabilities( p_vout->p_sys->p_channel,
556 printf("vcaps.format = 0x%x\n", vcaps.format);
557 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
558 vcaps.format == Pg_VIDEO_FORMAT_YUV420 ||
559 vcaps.format == Pg_VIDEO_FORMAT_YUY2 ||
560 vcaps.format == Pg_VIDEO_FORMAT_UYVY ||
561 vcaps.format == Pg_VIDEO_FORMAT_RGB555 ||
562 vcaps.format == Pg_VIDEO_FORMAT_RGB565 ||
563 vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
565 p_vout->p_sys->i_vc_flags = vcaps.flags;
566 p_vout->p_sys->i_vc_format = vcaps.format;
569 vcaps.size = sizeof( vcaps );
572 if( p_vout->p_sys->i_vc_format == 0 )
574 msg_Warn( p_vout, "need YV12, YUY2 or RGB8888 overlay" );
576 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
581 /* use video ram if we have enough available */
582 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
583 (minfo.bits_per_pixel != 8) &&
584 hwcaps.currently_available_video_ram >=
585 ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) )
587 p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
588 printf("Using video memory...\n");
591 p_vout->p_sys->i_img_type = minfo.type;
592 p_vout->p_sys->screen_dim.w = minfo.width;
593 p_vout->p_sys->screen_dim.h = minfo.height;
594 p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel;
596 switch( p_vout->p_sys->i_screen_depth )
599 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
600 p_vout->p_sys->i_bytes_per_pixel = 1;
601 p_vout->output.pf_setpalette = SetPalette;
605 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
606 p_vout->p_sys->i_bytes_per_pixel = 2;
607 p_vout->output.i_rmask = 0x7c00;
608 p_vout->output.i_gmask = 0x03e0;
609 p_vout->output.i_bmask = 0x001f;
613 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
614 p_vout->p_sys->i_bytes_per_pixel = 2;
615 p_vout->output.i_rmask = 0xf800;
616 p_vout->output.i_gmask = 0x07e0;
617 p_vout->output.i_bmask = 0x001f;
621 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
622 p_vout->p_sys->i_bytes_per_pixel = 3;
623 p_vout->output.i_rmask = 0xff0000;
624 p_vout->output.i_gmask = 0x00ff00;
625 p_vout->output.i_bmask = 0x0000ff;
630 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
631 p_vout->p_sys->i_bytes_per_pixel = 4;
632 p_vout->output.i_rmask = 0xff0000;
633 p_vout->output.i_gmask = 0x00ff00;
634 p_vout->output.i_bmask = 0x0000ff;
641 /*****************************************************************************
642 * QNXCreateWnd: create and realize the main window
643 *****************************************************************************/
644 static int QNXCreateWnd( vout_thread_t * p_vout )
647 PhPoint_t pos = { 0, 0 };
648 PgColor_t color = Pg_BLACK;
650 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
652 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
654 color = PgGetOverlayChromaColor();
658 /* fullscreen, set dimension */
659 if( p_vout->b_fullscreen )
661 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
662 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
663 p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
664 p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
667 /* set window parameters */
668 PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
669 PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
670 PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
671 PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VLC media player", 0 );
672 PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
673 PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
674 Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
675 PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
676 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
677 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
680 p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
681 if( p_vout->p_sys->p_window == NULL )
683 msg_Err( p_vout, "unable to create window" );
687 /* realize the window widget */
688 if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
690 msg_Err( p_vout, "unable to realize window widget" );
691 PtDestroyWidget( p_vout->p_sys->p_window );
695 /* get window frame size */
696 if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window,
697 &p_vout->p_sys->frame ) != 0 )
699 msg_Err( p_vout, "unable to get window frame size" );
700 PtDestroyWidget( p_vout->p_sys->p_window );
707 /*****************************************************************************
708 * QNXDestroyWnd: unrealize and destroy the main window
709 *****************************************************************************/
710 static int QNXDestroyWnd( vout_thread_t * p_vout )
712 /* destroy the window widget */
713 PtUnrealizeWidget( p_vout->p_sys->p_window );
714 // PtDestroyWidget( p_vout->p_sys->p_window );
716 /* destroy video channel */
717 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
719 PgDestroyVideoChannel( p_vout->p_sys->p_channel );
726 /*****************************************************************************
727 * NewPicture: allocate a picture
728 *****************************************************************************
729 * Returns 0 on success, -1 otherwise
730 *****************************************************************************/
731 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index )
733 /* We know the chroma, allocate a buffer which will be used
734 * directly by the decoder */
735 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
737 if( p_pic->p_sys == NULL )
742 switch( p_vout->p_sys->i_mode )
744 case MODE_NORMAL_MEM:
745 case MODE_SHARED_MEM:
746 /* create images for [shared] memory blit */
747 if( !( p_pic->p_sys->p_image = PhCreateImage( NULL,
748 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
749 p_vout->p_sys->i_img_type, NULL, 0,
750 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
751 msg_Err( p_vout, "cannot create image" );
752 free( p_pic->p_sys );
756 p_pic->p->p_pixels = p_pic->p_sys->p_image->image;
757 p_pic->p->i_lines = p_pic->p_sys->p_image->size.h;
758 p_pic->p->i_visible_lines = p_pic->p_sys->p_image->size.h;
759 p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl;
760 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
761 p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
762 * p_pic->p_sys->p_image->size.w;
767 /* create offscreen contexts for video memory blit */
768 if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
769 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
770 Pg_OSC_MEM_PAGE_ALIGN) ) == NULL )
772 msg_Err( p_vout, "unable to create offscreen context" );
773 free( p_pic->p_sys );
777 /* get context pointers */
778 if( ( p_pic->p_sys->p_buf[0] =
779 PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL )
781 msg_Err( p_vout, "unable to get offscreen context ptr" );
782 PhDCRelease ( p_pic->p_sys->p_ctx[0] );
783 p_pic->p_sys->p_ctx[0] = NULL;
784 free( p_pic->p_sys );
788 p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch;
789 memset( p_pic->p_sys->p_buf[0], 0,
790 p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h );
792 p_pic->p->p_pixels = p_pic->p_sys->p_buf[0];
793 p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h;
794 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[0]->dim.h;
795 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch;
796 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
797 p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
798 * p_pic->p_sys->p_ctx[0]->dim.w;
802 case MODE_VIDEO_OVERLAY:
805 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1;
806 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1;
807 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1;
811 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2;
812 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2;
813 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2;
816 p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] );
817 if( p_pic->p_sys->p_buf[Y_PLANE] == NULL )
819 msg_Err( p_vout, "unable to get video channel ctx ptr" );
823 switch (p_vout->p_sys->i_vc_format)
825 case Pg_VIDEO_FORMAT_YUV420:
826 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
828 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
829 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
831 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
832 p_pic->p_sys->p_buf[V_PLANE] == NULL )
834 msg_Err( p_vout, "unable to get video channel ctx ptr" );
838 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
839 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
840 p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
841 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
842 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
843 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
845 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
846 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
847 p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
848 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
849 p_pic->p[U_PLANE].i_pixel_pitch = 1;
850 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
852 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
853 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
854 p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
855 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
856 p_pic->p[V_PLANE].i_pixel_pitch = 1;
857 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
862 case Pg_VIDEO_FORMAT_YV12:
863 p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
865 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
866 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
868 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
869 p_pic->p_sys->p_buf[V_PLANE] == NULL )
871 msg_Err( p_vout, "unable to get video channel ctx ptr" );
875 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
876 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
877 p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
878 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
879 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
880 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
882 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
883 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
884 p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
885 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
886 p_pic->p[U_PLANE].i_pixel_pitch = 1;
887 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
889 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
890 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
891 p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
892 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
893 p_pic->p[V_PLANE].i_pixel_pitch = 1;
894 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
899 case Pg_VIDEO_FORMAT_UYVY:
900 case Pg_VIDEO_FORMAT_YUY2:
901 if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY)
903 p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
907 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
910 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
911 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
912 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
913 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
914 p_pic->p->i_pixel_pitch = 4;
915 p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
920 case Pg_VIDEO_FORMAT_RGB555:
921 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
922 p_vout->output.i_rmask = 0x001f;
923 p_vout->output.i_gmask = 0x03e0;
924 p_vout->output.i_bmask = 0x7c00;
926 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
927 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
928 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
929 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
930 p_pic->p->i_pixel_pitch = 2;
931 p_pic->p->i_visible_pitch = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
936 case Pg_VIDEO_FORMAT_RGB565:
937 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
938 p_vout->output.i_rmask = 0x001f;
939 p_vout->output.i_gmask = 0x07e0;
940 p_vout->output.i_bmask = 0xf800;
942 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
943 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
944 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
945 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
946 p_pic->p->i_pixel_pitch = 4;
947 p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
952 case Pg_VIDEO_FORMAT_RGB8888:
953 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
954 p_vout->output.i_rmask = 0x000000ff;
955 p_vout->output.i_gmask = 0x0000ff00;
956 p_vout->output.i_bmask = 0x00ff0000;
958 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
959 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
960 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
961 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
962 p_pic->p->i_pixel_pitch = 4;
963 p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
970 switch( p_vout->output.i_chroma )
972 #ifdef MODULE_NAME_IS_xvideo
973 case VLC_FOURCC('Y','2','1','1'):
975 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
976 + p_pic->p_sys->p_image->offsets[0];
977 p_pic->p->i_lines = p_vout->output.i_height;
978 p_pic->p->i_visible_lines = p_vout->output.i_height;
979 /* XXX: this just looks so plain wrong... check it out ! */
980 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
981 p_pic->p->i_pixel_pitch = 4;
982 p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
991 /* This shouldn't happen ! */
998 /*****************************************************************************
999 * FreePicture: destroy a picture allocated with NewPicture
1000 *****************************************************************************
1001 * Destroy XImage AND associated data. If using Shm, detach shared memory
1002 * segment from server and process, then free it. The XDestroyImage manpage
1003 * says that both the image structure _and_ the data pointed to by the
1004 * image structure are freed, so no need to free p_image->data.
1005 *****************************************************************************/
1006 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1008 if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
1009 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) &&
1010 p_pic->p_sys->p_image )
1012 PhReleaseImage( p_pic->p_sys->p_image );
1013 free( p_pic->p_sys->p_image );
1015 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
1016 p_pic->p_sys->p_ctx[0] )
1018 PhDCRelease( p_pic->p_sys->p_ctx[0] );
1021 free( p_pic->p_sys );
1025 static int ResizeOverlayOutput(vout_thread_t *p_vout)
1027 int i_width, i_height, i_x, i_y;
1029 PgScalerProps_t props;
1031 props.size = sizeof( props );
1032 props.format = p_vout->p_sys->i_vc_format;
1033 props.flags = Pg_SCALER_PROP_SCALER_ENABLE |
1034 Pg_SCALER_PROP_DOUBLE_BUFFER;
1036 /* enable chroma keying if available */
1037 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
1039 props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
1042 /* set viewport position */
1043 props.viewport.ul.x = p_vout->p_sys->pos.x;
1044 props.viewport.ul.y = p_vout->p_sys->pos.y;
1045 if( !p_vout->b_fullscreen )
1047 props.viewport.ul.x += p_vout->p_sys->frame.ul.x;
1048 props.viewport.ul.y += p_vout->p_sys->frame.ul.y;
1051 /* set viewport dimension */
1052 vout_PlacePicture( p_vout, p_vout->p_sys->dim.w,
1053 p_vout->p_sys->dim.h,
1054 &i_x, &i_y, &i_width, &i_height );
1056 props.viewport.ul.x += i_x;
1057 props.viewport.ul.y += i_y;
1058 props.viewport.lr.x = i_width + props.viewport.ul.x;
1059 props.viewport.lr.y = i_height + props.viewport.ul.y;
1061 /* set source dimension */
1062 props.src_dim.w = p_vout->output.i_width;
1063 props.src_dim.h = p_vout->output.i_height;
1065 /* configure scaler channel */
1066 i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props );
1070 msg_Err( p_vout, "unable to configure video channel" );
1078 /*****************************************************************************
1079 * SetPalette: sets an 8 bpp palette
1080 *****************************************************************************
1081 * This function sets the palette given as an argument. It does not return
1082 * anything, but could later send information on which colors it was unable
1084 *****************************************************************************/
1085 static void SetPalette( vout_thread_t *p_vout,
1086 uint16_t *red, uint16_t *green, uint16_t *blue )
1090 /* allocate palette */
1091 for( i = 0; i < 255; i++ )
1093 /* kludge: colors are indexed reversely because color 255 seems
1094 * to be reserved for black even if we try to set it to white */
1095 p_vout->p_sys->p_colors[ i ] = PgRGB( red[ i ] >> 8, green[ i ] >> 8, blue[ i ] >> 8 );