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>
38 #include <vlc_common.h>
39 #include <vlc_interface.h>
42 /*****************************************************************************
43 * vout_sys_t: video output QNX method descriptor
44 *****************************************************************************
45 * This structure is part of the video output thread descriptor.
46 * It describes the QNX specific properties of an output thread. QNX video
47 * output is performed through regular resizable windows. Windows can be
48 * dynamically resized to adapt to the size of the streams.
49 *****************************************************************************/
50 #define MAX_DIRECTBUFFERS 2
52 #define MODE_NORMAL_MEM 0
53 #define MODE_SHARED_MEM 1
54 #define MODE_VIDEO_MEM 2
55 #define MODE_VIDEO_OVERLAY 3
63 PtWidget_t * p_window;
65 /* Color palette for 8bpp */
66 PgColor_t p_colors[255];
68 /* [shared] memory blit */
71 /* video memory blit */
74 PgVideoChannel_t * p_channel;
79 int i_bytes_per_pixel;
82 /* position & dimensions */
92 /*****************************************************************************
93 * picture_sys_t: direct buffer method descriptor
94 *****************************************************************************
95 * This structure is part of the picture descriptor, it describes the
96 * XVideo specific properties of a direct buffer.
97 *****************************************************************************/
100 /* [shared] memory blit */
103 /* video memory blit and video overlay */
104 PdOffscreenContext_t * p_ctx[3]; /* 0: y, 1: u, 2: v */
109 /*****************************************************************************
111 *****************************************************************************/
112 static int QNXInit ( vout_thread_t * );
113 static void QNXEnd ( vout_thread_t * );
114 static int QNXManage ( vout_thread_t * );
115 static void QNXDisplay ( vout_thread_t *, picture_t * );
117 static int QNXInitDisplay ( vout_thread_t * );
118 static int QNXCreateWnd ( vout_thread_t * );
119 static int QNXDestroyWnd ( vout_thread_t * );
121 static int NewPicture ( vout_thread_t *, picture_t *, int );
122 static void FreePicture ( vout_thread_t *, picture_t * );
123 static int ResizeOverlayOutput ( vout_thread_t * );
124 static void SetPalette ( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
126 /*****************************************************************************
127 * OpenVideo: allocate QNX video thread output method
128 *****************************************************************************
129 * This function allocate and initialize a QNX vout method. It uses some of the
130 * vout properties to choose the window size, and change them according to the
131 * actual properties of the display.
132 *****************************************************************************/
133 int OpenVideo ( vlc_object_t *p_this )
135 vout_thread_t * p_vout = (vout_thread_t *)p_this;
137 /* init connection to photon */
138 if( PtInit( "/dev/photon" ) != 0 )
140 msg_Err( p_vout, "unable to connect to photon" );
144 /* allocate structure */
145 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
146 if( p_vout->p_sys == NULL )
149 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
151 p_vout->b_fullscreen = config_GetInt( p_vout, "fullscreen" );
152 p_vout->p_sys->i_mode = config_GetInt( p_vout, "overlay" ) ?
153 MODE_VIDEO_OVERLAY : MODE_VIDEO_MEM;
154 p_vout->p_sys->dim.w = p_vout->i_window_width;
155 p_vout->p_sys->dim.h = p_vout->i_window_height;
157 /* init display and create window */
158 if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) )
160 free( p_vout->p_sys );
164 p_vout->pf_init = QNXInit;
165 p_vout->pf_end = QNXEnd;
166 p_vout->pf_manage = QNXManage;
167 p_vout->pf_render = NULL;
168 p_vout->pf_display = QNXDisplay;
173 /*****************************************************************************
174 * QNXInit: initialize QNX video thread output method
175 *****************************************************************************
176 * This function create the buffers needed by the output thread. It is called
177 * at the beginning of the thread, but also each time the window is resized.
178 *****************************************************************************/
179 static int QNXInit( vout_thread_t *p_vout )
184 I_OUTPUTPICTURES = 0;
186 switch( p_vout->p_sys->i_mode )
188 case MODE_NORMAL_MEM:
189 case MODE_SHARED_MEM:
190 p_vout->output.i_width = p_vout->p_sys->dim.w;
191 p_vout->output.i_height = p_vout->p_sys->dim.h;
193 /* Assume we have square pixels */
194 p_vout->output.i_aspect = p_vout->p_sys->dim.w
195 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
199 p_vout->output.i_width = p_vout->p_sys->dim.w;
200 p_vout->output.i_height = p_vout->p_sys->dim.h;
202 /* Assume we have square pixels */
203 p_vout->output.i_aspect = p_vout->p_sys->dim.w
204 * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h;
207 case MODE_VIDEO_OVERLAY:
208 p_vout->output.i_width = p_vout->render.i_width;
209 p_vout->output.i_height = p_vout->render.i_height;
210 p_vout->output.i_aspect = p_vout->render.i_aspect;
212 if (ResizeOverlayOutput(p_vout))
219 /* This shouldn't happen ! */
223 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
224 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
228 /* Find an empty picture slot */
229 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
231 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
233 p_pic = p_vout->p_picture + i_index;
238 /* Allocate the picture */
239 if( p_pic == NULL || NewPicture( p_vout, p_pic, I_OUTPUTPICTURES ) )
244 p_pic->i_status = DESTROYED_PICTURE;
245 p_pic->i_type = DIRECT_PICTURE;
247 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
255 /*****************************************************************************
256 * QNXEnd: terminate QNX video thread output method
257 *****************************************************************************
258 * Destroy the buffers created by QNXInit. It is called at the end of
259 * the thread, but also each time the window is resized.
260 *****************************************************************************/
261 static void QNXEnd( vout_thread_t *p_vout )
265 /* Free the direct buffers we allocated */
266 for( i_index = I_OUTPUTPICTURES ; i_index ; )
269 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
273 /*****************************************************************************
274 * CloseVideo: destroy QNX video thread output method
275 *****************************************************************************
276 * Terminate an output method created by QNXCreate
277 *****************************************************************************/
278 void CloseVideo ( vlc_object_t *p_this )
280 vout_thread_t * p_vout = (vout_thread_t *)p_this;
282 /* destroy the window */
283 QNXDestroyWnd( p_vout );
285 /* destroy structure */
286 free( p_vout->p_sys );
289 /*****************************************************************************
290 * QNXManage: handle QNX events
291 *****************************************************************************
292 * This function should be called regularly by video output thread. It allows
293 * window resizing. It returns a non null value on error.
294 *****************************************************************************/
295 static int QNXManage( vout_thread_t *p_vout )
301 if (!vlc_object_alive (p_vout))
306 /* allocate buffer for event */
307 i_buflen = sizeof( PhEvent_t ) * 4;
308 if( ( p_event = malloc( i_buflen ) ) == NULL )
314 memset( p_event, 0, i_buflen );
315 i_ev = PhEventPeek( p_event, i_buflen );
317 if( i_ev == Ph_RESIZE_MSG )
319 i_buflen = PhGetMsgSize( p_event );
320 if( ( p_event = realloc( p_event, i_buflen ) ) == NULL )
323 else if( i_ev == Ph_EVENT_MSG )
325 PtEventHandler( p_event );
327 if( p_event->type == Ph_EV_WM )
329 PhWindowEvent_t *p_ev = PhGetData( p_event );
331 switch( p_ev->event_f )
334 p_vout->p_libvlc->b_die = true;
338 p_vout->p_sys->pos.x = p_ev->pos.x;
339 p_vout->p_sys->pos.y = p_ev->pos.y;
344 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
345 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
346 p_vout->p_sys->dim.w = p_ev->size.w;
347 p_vout->p_sys->dim.h = p_ev->size.h;
348 p_vout->i_changes |= VOUT_SIZE_CHANGE;
352 else if( p_event->type == Ph_EV_KEY )
354 PhKeyEvent_t *p_ev = PhGetData( p_event );
355 long i_key = p_ev->key_sym;
357 if( ( p_ev->key_flags & Pk_KF_Key_Down ) &&
358 ( p_ev->key_flags & Pk_KF_Sym_Valid ) )
364 p_vout->p_libvlc->b_die = true;
369 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
378 } while( i_ev != -1 && i_ev != 0 );
385 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
389 p_vout->b_fullscreen = !p_vout->b_fullscreen;
390 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
392 if( p_vout->b_fullscreen )
394 p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x;
395 p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y;
396 p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0;
397 dim.w = p_vout->p_sys->screen_dim.w + 1;
398 dim.h = p_vout->p_sys->screen_dim.h + 1;
402 p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x;
403 p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y;
404 dim.w = p_vout->p_sys->old_dim.w + 1;
405 dim.h = p_vout->p_sys->old_dim.h + 1;
408 /* modify render flags, border */
409 PtSetResource( p_vout->p_sys->p_window,
410 Pt_ARG_WINDOW_RENDER_FLAGS,
411 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
412 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
414 /* set position and dimension */
415 PtSetResource( p_vout->p_sys->p_window,
416 Pt_ARG_POS, &p_vout->p_sys->pos, 0 );
417 PtSetResource( p_vout->p_sys->p_window,
418 Pt_ARG_DIM, &dim, 0 );
420 /* mark as damaged to force redraw */
421 PtDamageWidget( p_vout->p_sys->p_window );
427 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
429 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
431 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
433 ResizeOverlayOutput(p_vout);
438 p_vout->output.i_width = p_vout->p_sys->dim.w;
439 p_vout->output.i_height = p_vout->p_sys->dim.h;
440 p_vout->i_changes |= VOUT_YUV_CHANGE;
443 if( QNXInit( p_vout ) )
445 msg_Err( p_vout, "cannot resize display" );
451 msg_Dbg( p_vout, "video display resized (%dx%d)",
452 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h );
456 * position change, move video channel
458 if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
460 ResizeOverlayOutput(p_vout);
463 return( i_ev == -1 );
466 /*****************************************************************************
467 * QNXDisplay: displays previously rendered output
468 *****************************************************************************
469 * This function send the currently rendered image to QNX server, wait until
470 * it is displayed and switch the two rendering buffer, preparing next frame.
471 *****************************************************************************/
472 static void QNXDisplay( vout_thread_t *p_vout, picture_t *p_pic )
474 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
475 p_vout->p_sys->i_mode == MODE_SHARED_MEM )
477 PhPoint_t pos = { 0, 0 };
479 PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) );
480 if (p_vout->p_sys->i_screen_depth == 8)
482 PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0);
484 PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 );
487 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM )
489 PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } };
491 // PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) );
492 PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc );
497 /*****************************************************************************
498 * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc
499 *****************************************************************************/
500 static int QNXInitDisplay( vout_thread_t * p_vout )
503 PgDisplaySettings_t cfg;
504 PgVideoModeInfo_t minfo;
506 /* get graphics card hw capabilities */
507 if( PgGetGraphicsHWCaps( &hwcaps ) != 0 )
509 msg_Err( p_vout, "unable to get gfx card capabilities" );
513 /* get current video mode */
514 if( PgGetVideoMode( &cfg ) != 0 )
516 msg_Err( p_vout, "unable to get current video mode" );
520 /* get video mode info */
521 if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 )
523 msg_Err( p_vout, "unable to get info for video mode" );
527 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
530 PgScalerCaps_t vcaps;
532 if( ( p_vout->p_sys->p_channel =
533 PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL )
535 msg_Err( p_vout, "unable to create video channel" );
536 printf("errno = %d\n", errno);
537 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
541 vcaps.size = sizeof( vcaps );
542 while( PgGetScalerCapabilities( p_vout->p_sys->p_channel,
545 printf("vcaps.format = 0x%x\n", vcaps.format);
546 if( vcaps.format == Pg_VIDEO_FORMAT_YV12 ||
547 vcaps.format == Pg_VIDEO_FORMAT_YUV420 ||
548 vcaps.format == Pg_VIDEO_FORMAT_YUY2 ||
549 vcaps.format == Pg_VIDEO_FORMAT_UYVY ||
550 vcaps.format == Pg_VIDEO_FORMAT_RGB555 ||
551 vcaps.format == Pg_VIDEO_FORMAT_RGB565 ||
552 vcaps.format == Pg_VIDEO_FORMAT_RGB8888 )
554 p_vout->p_sys->i_vc_flags = vcaps.flags;
555 p_vout->p_sys->i_vc_format = vcaps.format;
558 vcaps.size = sizeof( vcaps );
561 if( p_vout->p_sys->i_vc_format == 0 )
563 msg_Warn( p_vout, "need YV12, YUY2 or RGB8888 overlay" );
565 p_vout->p_sys->i_mode = MODE_NORMAL_MEM;
570 /* use video ram if we have enough available */
571 if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM &&
572 (minfo.bits_per_pixel != 8) &&
573 hwcaps.currently_available_video_ram >=
574 ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) )
576 p_vout->p_sys->i_mode = MODE_VIDEO_MEM;
577 printf("Using video memory...\n");
580 p_vout->p_sys->i_img_type = minfo.type;
581 p_vout->p_sys->screen_dim.w = minfo.width;
582 p_vout->p_sys->screen_dim.h = minfo.height;
583 p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel;
585 switch( p_vout->p_sys->i_screen_depth )
588 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
589 p_vout->p_sys->i_bytes_per_pixel = 1;
590 p_vout->output.pf_setpalette = SetPalette;
594 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
595 p_vout->p_sys->i_bytes_per_pixel = 2;
596 p_vout->output.i_rmask = 0x7c00;
597 p_vout->output.i_gmask = 0x03e0;
598 p_vout->output.i_bmask = 0x001f;
602 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
603 p_vout->p_sys->i_bytes_per_pixel = 2;
604 p_vout->output.i_rmask = 0xf800;
605 p_vout->output.i_gmask = 0x07e0;
606 p_vout->output.i_bmask = 0x001f;
610 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
611 p_vout->p_sys->i_bytes_per_pixel = 3;
612 p_vout->output.i_rmask = 0xff0000;
613 p_vout->output.i_gmask = 0x00ff00;
614 p_vout->output.i_bmask = 0x0000ff;
619 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
620 p_vout->p_sys->i_bytes_per_pixel = 4;
621 p_vout->output.i_rmask = 0xff0000;
622 p_vout->output.i_gmask = 0x00ff00;
623 p_vout->output.i_bmask = 0x0000ff;
630 /*****************************************************************************
631 * QNXCreateWnd: create and realize the main window
632 *****************************************************************************/
633 static int QNXCreateWnd( vout_thread_t * p_vout )
636 PhPoint_t pos = { 0, 0 };
637 PgColor_t color = Pg_BLACK;
639 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
641 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
643 color = PgGetOverlayChromaColor();
647 /* fullscreen, set dimension */
648 if( p_vout->b_fullscreen )
650 p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w;
651 p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h;
652 p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w;
653 p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h;
656 /* set window parameters */
657 PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 );
658 PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 );
659 PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 );
660 PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VLC media player", 0 );
661 PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE );
662 PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE,
663 Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE );
664 PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS,
665 p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE,
666 Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE );
669 p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args);
670 if( p_vout->p_sys->p_window == NULL )
672 msg_Err( p_vout, "unable to create window" );
676 /* realize the window widget */
677 if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 )
679 msg_Err( p_vout, "unable to realize window widget" );
680 PtDestroyWidget( p_vout->p_sys->p_window );
684 /* get window frame size */
685 if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window,
686 &p_vout->p_sys->frame ) != 0 )
688 msg_Err( p_vout, "unable to get window frame size" );
689 PtDestroyWidget( p_vout->p_sys->p_window );
696 /*****************************************************************************
697 * QNXDestroyWnd: unrealize and destroy the main window
698 *****************************************************************************/
699 static int QNXDestroyWnd( vout_thread_t * p_vout )
701 /* destroy the window widget */
702 PtUnrealizeWidget( p_vout->p_sys->p_window );
703 // PtDestroyWidget( p_vout->p_sys->p_window );
705 /* destroy video channel */
706 if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY )
708 PgDestroyVideoChannel( p_vout->p_sys->p_channel );
715 /*****************************************************************************
716 * NewPicture: allocate a picture
717 *****************************************************************************
718 * Returns 0 on success, -1 otherwise
719 *****************************************************************************/
720 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index )
722 /* We know the chroma, allocate a buffer which will be used
723 * directly by the decoder */
724 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
726 if( p_pic->p_sys == NULL )
731 switch( p_vout->p_sys->i_mode )
733 case MODE_NORMAL_MEM:
734 case MODE_SHARED_MEM:
735 /* create images for [shared] memory blit */
736 if( !( p_pic->p_sys->p_image = PhCreateImage( NULL,
737 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
738 p_vout->p_sys->i_img_type, NULL, 0,
739 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) {
740 msg_Err( p_vout, "cannot create image" );
741 free( p_pic->p_sys );
745 p_pic->p->p_pixels = p_pic->p_sys->p_image->image;
746 p_pic->p->i_lines = p_pic->p_sys->p_image->size.h;
747 p_pic->p->i_visible_lines = p_pic->p_sys->p_image->size.h;
748 p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl;
749 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
750 p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
751 * p_pic->p_sys->p_image->size.w;
756 /* create offscreen contexts for video memory blit */
757 if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0,
758 p_vout->p_sys->dim.w, p_vout->p_sys->dim.h,
759 Pg_OSC_MEM_PAGE_ALIGN) ) == NULL )
761 msg_Err( p_vout, "unable to create offscreen context" );
762 free( p_pic->p_sys );
766 /* get context pointers */
767 if( ( p_pic->p_sys->p_buf[0] =
768 PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL )
770 msg_Err( p_vout, "unable to get offscreen context ptr" );
771 PhDCRelease ( p_pic->p_sys->p_ctx[0] );
772 p_pic->p_sys->p_ctx[0] = NULL;
773 free( p_pic->p_sys );
777 p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch;
778 memset( p_pic->p_sys->p_buf[0], 0,
779 p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h );
781 p_pic->p->p_pixels = p_pic->p_sys->p_buf[0];
782 p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h;
783 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[0]->dim.h;
784 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch;
785 p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
786 p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel
787 * p_pic->p_sys->p_ctx[0]->dim.w;
791 case MODE_VIDEO_OVERLAY:
794 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1;
795 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1;
796 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1;
800 p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2;
801 p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2;
802 p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2;
805 p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] );
806 if( p_pic->p_sys->p_buf[Y_PLANE] == NULL )
808 msg_Err( p_vout, "unable to get video channel ctx ptr" );
812 switch (p_vout->p_sys->i_vc_format)
814 case Pg_VIDEO_FORMAT_YUV420:
815 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
817 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
818 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
820 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
821 p_pic->p_sys->p_buf[V_PLANE] == NULL )
823 msg_Err( p_vout, "unable to get video channel ctx ptr" );
827 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
828 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
829 p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
830 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
831 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
832 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
834 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
835 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
836 p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
837 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
838 p_pic->p[U_PLANE].i_pixel_pitch = 1;
839 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
841 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
842 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
843 p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
844 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
845 p_pic->p[V_PLANE].i_pixel_pitch = 1;
846 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
851 case Pg_VIDEO_FORMAT_YV12:
852 p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
854 p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] );
855 p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] );
857 if( p_pic->p_sys->p_buf[U_PLANE] == NULL ||
858 p_pic->p_sys->p_buf[V_PLANE] == NULL )
860 msg_Err( p_vout, "unable to get video channel ctx ptr" );
864 p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE];
865 p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
866 p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
867 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
868 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
869 p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch;
871 p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE];
872 p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
873 p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h;
874 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch;
875 p_pic->p[U_PLANE].i_pixel_pitch = 1;
876 p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch;
878 p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE];
879 p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
880 p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h;
881 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch;
882 p_pic->p[V_PLANE].i_pixel_pitch = 1;
883 p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch;
888 case Pg_VIDEO_FORMAT_UYVY:
889 case Pg_VIDEO_FORMAT_YUY2:
890 if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY)
892 p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
896 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
899 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
900 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
901 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
902 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
903 p_pic->p->i_pixel_pitch = 4;
904 p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
909 case Pg_VIDEO_FORMAT_RGB555:
910 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
911 p_vout->output.i_rmask = 0x001f;
912 p_vout->output.i_gmask = 0x03e0;
913 p_vout->output.i_bmask = 0x7c00;
915 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
916 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
917 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
918 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
919 p_pic->p->i_pixel_pitch = 2;
920 p_pic->p->i_visible_pitch = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
925 case Pg_VIDEO_FORMAT_RGB565:
926 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
927 p_vout->output.i_rmask = 0x001f;
928 p_vout->output.i_gmask = 0x07e0;
929 p_vout->output.i_bmask = 0xf800;
931 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
932 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
933 p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
934 p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch;
935 p_pic->p->i_pixel_pitch = 4;
936 p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w;
941 case Pg_VIDEO_FORMAT_RGB8888:
942 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
943 p_vout->output.i_rmask = 0x000000ff;
944 p_vout->output.i_gmask = 0x0000ff00;
945 p_vout->output.i_bmask = 0x00ff0000;
947 p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE];
948 p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h;
949 p_pic->p->i_visible_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;
959 switch( p_vout->output.i_chroma )
961 #ifdef MODULE_NAME_IS_xvideo
962 case VLC_FOURCC('Y','2','1','1'):
964 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
965 + p_pic->p_sys->p_image->offsets[0];
966 p_pic->p->i_lines = p_vout->output.i_height;
967 p_pic->p->i_visible_lines = p_vout->output.i_height;
968 /* XXX: this just looks so plain wrong... check it out ! */
969 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
970 p_pic->p->i_pixel_pitch = 4;
971 p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
980 /* This shouldn't happen ! */
987 /*****************************************************************************
988 * FreePicture: destroy a picture allocated with NewPicture
989 *****************************************************************************
990 * Destroy XImage AND associated data. If using Shm, detach shared memory
991 * segment from server and process, then free it. The XDestroyImage manpage
992 * says that both the image structure _and_ the data pointed to by the
993 * image structure are freed, so no need to free p_image->data.
994 *****************************************************************************/
995 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
997 if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM ||
998 p_vout->p_sys->i_mode == MODE_SHARED_MEM ) &&
999 p_pic->p_sys->p_image )
1001 PhReleaseImage( p_pic->p_sys->p_image );
1002 free( p_pic->p_sys->p_image );
1004 else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM &&
1005 p_pic->p_sys->p_ctx[0] )
1007 PhDCRelease( p_pic->p_sys->p_ctx[0] );
1010 free( p_pic->p_sys );
1014 static int ResizeOverlayOutput(vout_thread_t *p_vout)
1016 int i_width, i_height, i_x, i_y;
1018 PgScalerProps_t props;
1020 props.size = sizeof( props );
1021 props.format = p_vout->p_sys->i_vc_format;
1022 props.flags = Pg_SCALER_PROP_SCALER_ENABLE |
1023 Pg_SCALER_PROP_DOUBLE_BUFFER;
1025 /* enable chroma keying if available */
1026 if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY )
1028 props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE;
1031 /* set viewport position */
1032 props.viewport.ul.x = p_vout->p_sys->pos.x;
1033 props.viewport.ul.y = p_vout->p_sys->pos.y;
1034 if( !p_vout->b_fullscreen )
1036 props.viewport.ul.x += p_vout->p_sys->frame.ul.x;
1037 props.viewport.ul.y += p_vout->p_sys->frame.ul.y;
1040 /* set viewport dimension */
1041 vout_PlacePicture( p_vout, p_vout->p_sys->dim.w,
1042 p_vout->p_sys->dim.h,
1043 &i_x, &i_y, &i_width, &i_height );
1045 props.viewport.ul.x += i_x;
1046 props.viewport.ul.y += i_y;
1047 props.viewport.lr.x = i_width + props.viewport.ul.x;
1048 props.viewport.lr.y = i_height + props.viewport.ul.y;
1050 /* set source dimension */
1051 props.src_dim.w = p_vout->output.i_width;
1052 props.src_dim.h = p_vout->output.i_height;
1054 /* configure scaler channel */
1055 i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props );
1059 msg_Err( p_vout, "unable to configure video channel" );
1067 /*****************************************************************************
1068 * SetPalette: sets an 8 bpp palette
1069 *****************************************************************************
1070 * This function sets the palette given as an argument. It does not return
1071 * anything, but could later send information on which colors it was unable
1073 *****************************************************************************/
1074 static void SetPalette( vout_thread_t *p_vout,
1075 uint16_t *red, uint16_t *green, uint16_t *blue )
1079 /* allocate palette */
1080 for( i = 0; i < 255; i++ )
1082 /* kludge: colors are indexed reversely because color 255 seems
1083 * to be reserved for black even if we try to set it to white */
1084 p_vout->p_sys->p_colors[ i ] = PgRGB( red[ i ] >> 8, green[ i ] >> 8, blue[ i ] >> 8 );