1 /*****************************************************************************
2 * qte.cpp : QT Embedded plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 1998-2003 VideoLAN
5 * $Id: qte.cpp,v 1.22 2004/03/03 20:39:52 gbazin Exp $
7 * Authors: Gerald Hansink <gerald.hansink@ordain.nl>
8 * Jean-Paul Saman <jpsaman@wxs.nl>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
29 /*****************************************************************************
31 * - written for ipaq, so hardcoded assumptions specific for ipaq...
33 * - no "mouse events" handling
35 *****************************************************************************/
39 #include <errno.h> /* ENOMEM */
40 #include <stdlib.h> /* free() */
41 #include <string.h> /* strerror() */
47 #ifdef HAVE_MACHINE_PARAM_H
49 # include <machine/param.h>
50 # include <sys/types.h> /* typedef ushort */
55 # include <netinet/in.h> /* BSD: struct in_addr */
59 # include <sys/shm.h> /* shmget(), shmctl() */
63 #include <qapplication.h>
67 # define USE_DIRECT_PAINTER
68 # include <qdirectpainter_qws.h>
69 # include <qgfxraster_qws.h>
76 /*****************************************************************************
78 *****************************************************************************/
79 #define DISPLAY_TEXT N_("QT Embedded display name")
80 #define DISPLAY_LONGTEXT N_( \
81 "Specify the Qt Embedded hardware display you want to use. " \
82 "By default VLC will use the value of the DISPLAY environment variable.")
84 /*****************************************************************************
86 *****************************************************************************/
87 static int Open ( vlc_object_t * );
88 static void Close ( vlc_object_t * );
89 static void Render ( vout_thread_t *, picture_t * );
90 static void Display ( vout_thread_t *, picture_t * );
91 static int Manage ( vout_thread_t * );
92 static int Init ( vout_thread_t * );
93 static void End ( vout_thread_t * );
95 static int OpenDisplay ( vout_thread_t * );
96 static void CloseDisplay( vout_thread_t * );
98 static int NewPicture ( vout_thread_t *, picture_t * );
99 static void FreePicture ( vout_thread_t *, picture_t * );
101 static void ToggleFullScreen ( vout_thread_t * );
103 static void RunQtThread( event_thread_t *p_event );
106 /*****************************************************************************
107 * Exported prototypes
108 *****************************************************************************/
113 // add_category_hint( N_("QT Embedded"), NULL );
114 // add_string( "qte-display", "landscape", NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT);
115 set_description( _("QT Embedded video output") );
116 set_capability( "video output", 70 );
117 add_shortcut( "qte" );
118 set_callbacks( Open, Close);
123 /*****************************************************************************
124 * Seeking function TODO: put this in a generic location !
125 *****************************************************************************/
126 static inline void vout_Seek( off_t i_seek )
130 /*****************************************************************************
131 * Open: allocate video thread output method
132 *****************************************************************************/
133 static int Open( vlc_object_t *p_this )
135 vout_thread_t * p_vout = (vout_thread_t *)p_this;
137 /* Allocate structure */
138 p_vout->p_sys = (struct vout_sys_t*) malloc( sizeof( struct vout_sys_t ) );
140 if( p_vout->p_sys == NULL )
142 msg_Err( p_vout, "out of memory" );
146 p_vout->pf_init = Init;
147 p_vout->pf_end = End;
148 p_vout->pf_manage = Manage;
149 p_vout->pf_render = NULL; //Render;
150 p_vout->pf_display = Display;
153 p_vout->p_sys->p_qte_main =
154 module_Need( p_this, "gui-helper", "qte", VLC_TRUE );
155 if( p_vout->p_sys->p_qte_main == NULL )
157 free( p_vout->p_sys );
162 if (OpenDisplay(p_vout))
164 msg_Err( p_vout, "Cannot set up qte video output" );
171 /*****************************************************************************
172 * CloseVideo: destroy Sys video thread output method
173 *****************************************************************************
174 * Terminate an output method created by Open
175 *****************************************************************************/
176 static void Close ( vlc_object_t *p_this )
178 vout_thread_t * p_vout = (vout_thread_t *)p_this;
180 msg_Dbg( p_vout, "close" );
181 if( p_vout->p_sys->p_event )
183 vlc_object_detach( p_vout->p_sys->p_event );
185 /* Kill RunQtThread */
186 p_vout->p_sys->p_event->b_die = VLC_TRUE;
187 CloseDisplay(p_vout);
189 vlc_thread_join( p_vout->p_sys->p_event );
190 vlc_object_destroy( p_vout->p_sys->p_event );
194 msg_Dbg( p_vout, "releasing gui-helper" );
195 module_Unneed( p_vout, p_vout->p_sys->p_qte_main );
200 free( p_vout->p_sys );
201 p_vout->p_sys = NULL;
205 /*****************************************************************************
206 * Init: initialize video thread output method
207 *****************************************************************************
208 * This function create the buffers needed by the output thread. It is called
209 * at the beginning of the thread, but also each time the window is resized.
210 *****************************************************************************/
211 static int Init( vout_thread_t *p_vout )
215 int dd = QPixmap::defaultDepth();
217 I_OUTPUTPICTURES = 0;
219 p_vout->output.i_chroma = (dd == 16) ? VLC_FOURCC('R','V','1','6'): VLC_FOURCC('R','V','3','2');
220 p_vout->output.i_rmask = 0xf800;
221 p_vout->output.i_gmask = 0x07e0;
222 p_vout->output.i_bmask = 0x001f;
224 /* All we have is an RGB image with square pixels */
225 p_vout->output.i_width = p_vout->p_sys->i_width;
226 p_vout->output.i_height = p_vout->p_sys->i_height;
227 if( !p_vout->b_fullscreen )
229 p_vout->output.i_aspect = p_vout->output.i_width
231 / p_vout->output.i_height;
235 p_vout->output.i_aspect = p_vout->render.i_aspect;
238 msg_Dbg( p_vout, "Init (h=%d,w=%d,aspect=%d)",p_vout->output.i_height,p_vout->output.i_width,p_vout->output.i_aspect );
240 /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
241 while( I_OUTPUTPICTURES < QTE_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 ) )
261 p_pic->i_status = DESTROYED_PICTURE;
262 p_pic->i_type = DIRECT_PICTURE;
264 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
273 /*****************************************************************************
274 * Render: render previously calculated output
275 *****************************************************************************/
276 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
281 /*****************************************************************************
282 * Display: displays previously rendered output
283 *****************************************************************************
284 * This function sends the currently rendered image to screen.
285 *****************************************************************************/
286 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
288 unsigned int x, y, w, h;
290 vout_PlacePicture( p_vout, p_vout->output.i_width, p_vout->output.i_height,
293 msg_Dbg(p_vout, "+qte::Display( p_vout, i_width=%d, i_height=%d, x=%u, y=%u, w=%u, h=%u",
294 p_vout->output.i_width, p_vout->output.i_height, x, y, w, h );
297 if(p_vout->p_sys->p_VideoWidget)
299 // shameless borrowed from opie mediaplayer....
300 #ifndef USE_DIRECT_PAINTER
301 msg_Dbg(p_vout, "not using direct painter");
302 QPainter p(p_vout->p_sys->p_VideoWidget);
305 int dd = QPixmap::defaultDepth();
306 int bytes = ( dd == 16 ) ? 2 : 4;
309 QImage rotatedFrame( rw, rh, bytes << 3 );
311 ushort* in = (ushort*)p_pic->p_sys->pQImage->bits();
312 ushort* out = (ushort*)rotatedFrame.bits();
314 int spl = rotatedFrame.bytesPerLine() / bytes;
315 for (int x=0; x<h; x++)
319 ushort* lout = out++ + (w - 1)*spl;
320 for (int y=0; y<w; y++)
328 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
329 for (int y=0; y<w; y++)
331 *lout=*((ulong*)in)++;
337 p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh );
339 QDirectPainter p(p_vout->p_sys->p_VideoWidget);
340 p.transformOrientation();
341 // just copy the image to the frame buffer...
342 memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep());
347 /*****************************************************************************
348 * Manage: handle Qte events
349 *****************************************************************************
350 * This function should be called regularly by video output thread. It manages
351 * Qte events and allows window resizing. It returns a non null value on
353 *****************************************************************************/
354 static int Manage( vout_thread_t *p_vout )
356 // msg_Dbg( p_vout, "Manage" );
358 /* Fullscreen change */
359 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
361 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
363 // p_vout->p_sys->b_cursor_autohidden = 0;
364 // SDL_ShowCursor( p_vout->p_sys->b_cursor &&
365 // ! p_vout->p_sys->b_cursor_autohidden );
367 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
368 p_vout->i_changes |= VOUT_SIZE_CHANGE;
374 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
376 msg_Dbg( p_vout, "video display resized (%dx%d)",
377 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
379 CloseDisplay( p_vout );
380 OpenDisplay( p_vout );
382 /* We don't need to signal the vout thread about the size change if
383 * we can handle rescaling ourselves */
384 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
388 // if( ! p_vout->p_sys->b_cursor_autohidden &&
389 // ( mdate() - p_vout->p_sys->i_lastmoved > 2000000 ) )
391 // /* Hide the mouse automatically */
392 // p_vout->p_sys->b_cursor_autohidden = 1;
393 // SDL_ShowCursor( 0 );
396 // if( p_vout->p_vlc->b_die )
397 // p_vout->p_sys->bRunning = FALSE;
402 /*****************************************************************************
403 * End: terminate video thread output method
404 *****************************************************************************
405 * Destroy the buffers created by vout_Init. It is called at the end of
406 * the thread, but also each time the window is resized.
407 *****************************************************************************/
408 static void End( vout_thread_t *p_vout )
412 /* Free the direct buffers we allocated */
413 for( i_index = I_OUTPUTPICTURES ; i_index ; )
416 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
421 /*****************************************************************************
422 * NewPicture: allocate a picture
423 *****************************************************************************
424 * Returns 0 on success, -1 otherwise
425 *****************************************************************************/
426 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
428 int dd = QPixmap::defaultDepth();
430 p_pic->p_sys = (picture_sys_t*) malloc( sizeof( picture_sys_t ) );
431 if( p_pic->p_sys == NULL )
436 /* Create the display */
437 p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
438 p_vout->output.i_height, dd );
440 if(p_pic->p_sys->pQImage == NULL)
448 p_pic->p->i_pixel_pitch = 1;
452 p_pic->p->i_pixel_pitch = 2;
456 p_pic->p->i_pixel_pitch = 4;
462 p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
463 p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
464 p_pic->p->i_lines = p_vout->output.i_height;
465 p_pic->p->i_visible_pitch =
466 p_pic->p->i_pixel_pitch * p_vout->output.i_width;
473 /*****************************************************************************
474 * FreePicture: destroy a picture allocated with NewPicture
475 *****************************************************************************/
476 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
478 delete p_pic->p_sys->pQImage;
481 /*****************************************************************************
482 * ToggleFullScreen: Enable or disable full screen mode
483 *****************************************************************************
484 * This function will switch between fullscreen and window mode.
486 *****************************************************************************/
487 static void ToggleFullScreen ( vout_thread_t *p_vout )
489 if ( p_vout->b_fullscreen )
490 p_vout->p_sys->p_VideoWidget->showFullScreen();
492 p_vout->p_sys->p_VideoWidget->showNormal();
494 p_vout->b_fullscreen = !p_vout->b_fullscreen;
497 /*****************************************************************************
498 * OpenDisplay: create qte applicaton / window
499 *****************************************************************************
500 * Create a window according to video output given size, and set other
501 * properties according to the display properties.
502 *****************************************************************************/
503 static int OpenDisplay( vout_thread_t *p_vout )
505 /* for displaying the vout in a qt window we need the QtApplication */
506 p_vout->p_sys->p_QApplication = NULL;
507 p_vout->p_sys->p_VideoWidget = NULL;
509 p_vout->p_sys->p_event = (event_thread_t*) vlc_object_create( p_vout, sizeof(event_thread_t) );
510 p_vout->p_sys->p_event->p_vout = p_vout;
512 /* Initializations */
513 #if 1 /* FIXME: I need an event queue to handle video output size changes. */
514 p_vout->b_fullscreen = VLC_TRUE;
517 /* Set main window's size */
518 QWidget *desktop = p_vout->p_sys->p_QApplication->desktop();
519 p_vout->p_sys->i_width = p_vout->b_fullscreen ? desktop->height() :
520 p_vout->i_window_width;
521 p_vout->p_sys->i_height = p_vout->b_fullscreen ? desktop->width() :
522 p_vout->i_window_height;
524 #if 0 /* FIXME: I need an event queue to handle video output size changes. */
525 /* Update dimensions */
526 p_vout->i_changes |= VOUT_SIZE_CHANGE;
527 p_vout->i_window_width = p_vout->p_sys->i_width;
528 p_vout->i_window_height = p_vout->p_sys->i_height;
531 msg_Dbg( p_vout, "OpenDisplay (h=%d,w=%d)",p_vout->p_sys->i_height,p_vout->p_sys->i_width);
533 /* create thread to exec the qpe application */
534 if ( vlc_thread_create( p_vout->p_sys->p_event, "QT Embedded Thread",
536 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE) )
538 msg_Err( p_vout, "cannot create QT Embedded Thread" );
539 vlc_object_destroy( p_vout->p_sys->p_event );
540 p_vout->p_sys->p_event = NULL;
544 if( p_vout->p_sys->p_event->b_error )
546 msg_Err( p_vout, "RunQtThread failed" );
550 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
551 msg_Dbg( p_vout, "RunQtThread running" );
553 // just wait until the crew is complete...
554 while(p_vout->p_sys->p_VideoWidget == NULL)
562 /*****************************************************************************
563 * CloseDisplay: destroy the window
564 *****************************************************************************/
565 static void CloseDisplay( vout_thread_t *p_vout )
567 // quit qt application loop
568 msg_Dbg( p_vout, "destroying Qt Window" );
570 if(p_vout->p_sys->p_QApplication)
572 p_vout->p_sys->bRunning = FALSE;
573 while(p_vout->p_sys->p_VideoWidget)
579 if (p_vout->p_sys->p_QApplication)
580 p_vout->p_sys->p_QApplication->quit();
584 /*****************************************************************************
585 * main loop of qtapplication
586 *****************************************************************************/
587 static void RunQtThread(event_thread_t *p_event)
589 msg_Dbg( p_event->p_vout, "RunQtThread Starting" );
594 p_event->p_vout->p_sys->p_QApplication = qApp;
595 p_event->p_vout->p_sys->bOwnsQApp = FALSE;
596 p_event->p_vout->p_sys->p_VideoWidget = qApp->mainWidget();
597 msg_Dbg( p_event->p_vout, "RunQtThread applicaton attached" );
603 QApplication* pApp = new QApplication(argc, NULL);
606 p_event->p_vout->p_sys->p_QApplication = pApp;
607 p_event->p_vout->p_sys->bOwnsQApp = TRUE;
609 QWidget* pWidget = new QWidget();
612 p_event->p_vout->p_sys->p_VideoWidget = pWidget;
616 /* signal the creation of the window */
617 vlc_thread_ready( p_event );
618 msg_Dbg( p_event->p_vout, "RunQtThread ready" );
620 if (p_event->p_vout->p_sys->p_QApplication)
622 /* Set default window width and heigh to exactly preferred size. */
623 QWidget *desktop = p_event->p_vout->p_sys->p_QApplication->desktop();
624 p_event->p_vout->p_sys->p_VideoWidget->setMinimumWidth( 10 );
625 p_event->p_vout->p_sys->p_VideoWidget->setMinimumHeight( 10 );
626 p_event->p_vout->p_sys->p_VideoWidget->setBaseSize( p_event->p_vout->p_sys->i_width,
627 p_event->p_vout->p_sys->i_height );
628 p_event->p_vout->p_sys->p_VideoWidget->setMaximumWidth( desktop->width() );
629 p_event->p_vout->p_sys->p_VideoWidget->setMaximumHeight( desktop->height() );
630 /* Check on fullscreen */
631 if (p_event->p_vout->b_fullscreen)
632 p_event->p_vout->p_sys->p_VideoWidget->showFullScreen();
634 p_event->p_vout->p_sys->p_VideoWidget->showNormal();
636 p_event->p_vout->p_sys->p_VideoWidget->show();
637 p_event->p_vout->p_sys->bRunning = TRUE;
640 while(!p_event->b_die && p_event->p_vout->p_sys->bRunning)
642 /* Check if we are asked to exit */
649 // run the main loop of qtapplication until someone says: 'quit'
650 p_event->p_vout->p_sys->pcQApplication->exec();
654 #ifndef NEED_QTE_MAIN
655 if(p_event->p_vout->p_sys->p_QApplication)
657 delete p_event->p_vout->p_sys->p_VideoWidget;
658 p_event->p_vout->p_sys->p_VideoWidget = NULL;
659 delete p_event->p_vout->p_sys->p_QApplication;
660 p_event->p_vout->p_sys->p_QApplication = NULL;
663 p_event->p_vout->p_sys->p_VideoWidget = NULL;
666 msg_Dbg( p_event->p_vout, "RunQtThread terminating" );