1 /*****************************************************************************
2 * qte.cpp : QT Embedded plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 1998-2003 the VideoLAN team
7 * Authors: Gerald Hansink <gerald.hansink@ordina.nl>
8 * Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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 */
45 #include <vlc_common.h>
46 #include <vlc_plugin.h>
47 #include <vlc_interface.h>
50 #ifdef HAVE_MACHINE_PARAM_H
52 # include <machine/param.h>
53 # include <sys/types.h> /* typedef ushort */
58 # include <netinet/in.h> /* BSD: struct in_addr */
62 # include <sys/shm.h> /* shmget(), shmctl() */
66 #include <qapplication.h>
70 # define USE_DIRECT_PAINTER
71 # include <qdirectpainter_qws.h>
72 # include <qgfxraster_qws.h>
79 /*****************************************************************************
81 *****************************************************************************/
82 #define DISPLAY_TEXT N_("QT Embedded display")
83 #define DISPLAY_LONGTEXT N_( \
84 "Qt Embedded hardware display to use. " \
85 "By default VLC will use the value of the DISPLAY environment variable.")
87 /*****************************************************************************
89 *****************************************************************************/
90 static int Open ( vlc_object_t * );
91 static void Close ( vlc_object_t * );
92 static void Render ( vout_thread_t *, picture_t * );
93 static void Display ( vout_thread_t *, picture_t * );
94 static int Manage ( vout_thread_t * );
95 static int Init ( vout_thread_t * );
96 static void End ( vout_thread_t * );
98 static int OpenDisplay ( vout_thread_t * );
99 static void CloseDisplay( vout_thread_t * );
101 static int NewPicture ( vout_thread_t *, picture_t * );
102 static void FreePicture ( vout_thread_t *, picture_t * );
104 static void ToggleFullScreen ( vout_thread_t * );
106 static void* RunQtThread( vlc_object_t *p_this );
109 /*****************************************************************************
110 * Exported prototypes
111 *****************************************************************************/
116 set_category( CAT_VIDEO );
117 set_subcategory( SUBCAT_VIDEO_VOUT );
118 // add_category_hint( N_("QT Embedded"), NULL );
119 // add_string( "qte-display", "landscape", NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT);
120 set_description( N_("QT Embedded video output") );
121 set_capability( "video output", 70 );
122 add_shortcut( "qte" );
123 set_callbacks( Open, Close);
128 /*****************************************************************************
129 * Seeking function TODO: put this in a generic location !
130 *****************************************************************************/
131 static inline void vout_Seek( off_t i_seek )
135 /*****************************************************************************
136 * Open: allocate video thread output method
137 *****************************************************************************/
138 static int Open( vlc_object_t *p_this )
140 vout_thread_t * p_vout = (vout_thread_t *)p_this;
142 /* Allocate structure */
143 p_vout->p_sys = (struct vout_sys_t*) malloc( sizeof( struct vout_sys_t ) );
145 if( p_vout->p_sys == NULL )
148 p_vout->pf_init = Init;
149 p_vout->pf_end = End;
150 p_vout->pf_manage = Manage;
151 p_vout->pf_render = NULL; //Render;
152 p_vout->pf_display = Display;
155 p_vout->p_sys->p_qte_main =
156 module_Need( p_this, "gui-helper", "qte", true );
157 if( p_vout->p_sys->p_qte_main == NULL )
159 free( p_vout->p_sys );
164 if (OpenDisplay(p_vout))
166 msg_Err( p_vout, "Cannot set up qte video output" );
173 /*****************************************************************************
174 * CloseVideo: destroy Sys video thread output method
175 *****************************************************************************
176 * Terminate an output method created by Open
177 *****************************************************************************/
178 static void Close ( vlc_object_t *p_this )
180 vout_thread_t * p_vout = (vout_thread_t *)p_this;
182 msg_Dbg( p_vout, "close" );
183 if( p_vout->p_sys->p_event )
185 vlc_object_detach( p_vout->p_sys->p_event );
187 /* Kill RunQtThread */
188 vlc_object_kill( p_vout->p_sys->p_event );
189 CloseDisplay(p_vout);
191 vlc_thread_join( p_vout->p_sys->p_event );
192 vlc_object_release( p_vout->p_sys->p_event );
196 msg_Dbg( p_vout, "releasing gui-helper" );
197 module_Unneed( p_vout, p_vout->p_sys->p_qte_main );
202 free( p_vout->p_sys );
203 p_vout->p_sys = NULL;
207 /*****************************************************************************
208 * Init: initialize video thread output method
209 *****************************************************************************
210 * This function create the buffers needed by the output thread. It is called
211 * at the beginning of the thread, but also each time the window is resized.
212 *****************************************************************************/
213 static int Init( vout_thread_t *p_vout )
217 int dd = QPixmap::defaultDepth();
219 I_OUTPUTPICTURES = 0;
221 p_vout->output.i_chroma = (dd == 16) ? VLC_FOURCC('R','V','1','6'): VLC_FOURCC('R','V','3','2');
222 p_vout->output.i_rmask = 0xf800;
223 p_vout->output.i_gmask = 0x07e0;
224 p_vout->output.i_bmask = 0x001f;
226 /* All we have is an RGB image with square pixels */
227 p_vout->output.i_width = p_vout->p_sys->i_width;
228 p_vout->output.i_height = p_vout->p_sys->i_height;
229 if( !p_vout->b_fullscreen )
231 p_vout->output.i_aspect = p_vout->output.i_width
233 / p_vout->output.i_height;
237 p_vout->output.i_aspect = p_vout->render.i_aspect;
240 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 );
242 /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
243 while( I_OUTPUTPICTURES < QTE_MAX_DIRECTBUFFERS )
247 /* Find an empty picture slot */
248 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
250 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
252 p_pic = p_vout->p_picture + i_index;
257 /* Allocate the picture */
258 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
263 p_pic->i_status = DESTROYED_PICTURE;
264 p_pic->i_type = DIRECT_PICTURE;
266 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
275 /*****************************************************************************
276 * Render: render previously calculated output
277 *****************************************************************************/
278 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
283 /*****************************************************************************
284 * Display: displays previously rendered output
285 *****************************************************************************
286 * This function sends the currently rendered image to screen.
287 *****************************************************************************/
288 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
290 unsigned int x, y, w, h;
292 vout_PlacePicture( p_vout, p_vout->output.i_width, p_vout->output.i_height,
295 msg_Dbg(p_vout, "+qte::Display( p_vout, i_width=%d, i_height=%d, x=%u, y=%u, w=%u, h=%u",
296 p_vout->output.i_width, p_vout->output.i_height, x, y, w, h );
299 if(p_vout->p_sys->p_VideoWidget)
301 // shameless borrowed from opie mediaplayer....
302 #ifndef USE_DIRECT_PAINTER
303 msg_Dbg(p_vout, "not using direct painter");
304 QPainter p(p_vout->p_sys->p_VideoWidget);
307 int dd = QPixmap::defaultDepth();
308 int bytes = ( dd == 16 ) ? 2 : 4;
311 QImage rotatedFrame( rw, rh, bytes << 3 );
313 ushort* in = (ushort*)p_pic->p_sys->pQImage->bits();
314 ushort* out = (ushort*)rotatedFrame.bits();
316 int spl = rotatedFrame.bytesPerLine() / bytes;
317 for (int x=0; x<h; x++)
321 ushort* lout = out++ + (w - 1)*spl;
322 for (int y=0; y<w; y++)
330 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
331 for (int y=0; y<w; y++)
333 *lout=*((ulong*)in)++;
339 p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh );
341 QDirectPainter p(p_vout->p_sys->p_VideoWidget);
342 p.transformOrientation();
343 // just copy the image to the frame buffer...
344 memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep());
349 /*****************************************************************************
350 * Manage: handle Qte events
351 *****************************************************************************
352 * This function should be called regularly by video output thread. It manages
353 * Qte events and allows window resizing. It returns a non null value on
355 *****************************************************************************/
356 static int Manage( vout_thread_t *p_vout )
358 // msg_Dbg( p_vout, "Manage" );
360 /* Fullscreen change */
361 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
363 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
365 // p_vout->p_sys->b_cursor_autohidden = 0;
366 // SDL_ShowCursor( p_vout->p_sys->b_cursor &&
367 // ! p_vout->p_sys->b_cursor_autohidden );
369 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
370 p_vout->i_changes |= VOUT_SIZE_CHANGE;
376 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
378 msg_Dbg( p_vout, "video display resized (%dx%d)",
379 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
381 CloseDisplay( p_vout );
382 OpenDisplay( p_vout );
384 /* We don't need to signal the vout thread about the size change if
385 * we can handle rescaling ourselves */
386 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
390 // if( ! p_vout->p_sys->b_cursor_autohidden &&
391 // ( mdate() - p_vout->p_sys->i_lastmoved >
392 // p_vout->p_sys->i_mouse_hide_timeout ) )
394 // /* Hide the mouse automatically */
395 // p_vout->p_sys->b_cursor_autohidden = 1;
396 // SDL_ShowCursor( 0 );
399 // if( !vlc_object_alive (p_vout->p_libvlc) )
400 // p_vout->p_sys->bRunning = FALSE;
405 /*****************************************************************************
406 * End: terminate video thread output method
407 *****************************************************************************
408 * Destroy the buffers created by vout_Init. It is called at the end of
409 * the thread, but also each time the window is resized.
410 *****************************************************************************/
411 static void End( vout_thread_t *p_vout )
415 /* Free the direct buffers we allocated */
416 for( i_index = I_OUTPUTPICTURES ; i_index ; )
419 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
424 /*****************************************************************************
425 * NewPicture: allocate a picture
426 *****************************************************************************
427 * Returns 0 on success, -1 otherwise
428 *****************************************************************************/
429 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
431 int dd = QPixmap::defaultDepth();
433 p_pic->p_sys = (picture_sys_t*) malloc( sizeof( picture_sys_t ) );
434 if( p_pic->p_sys == NULL )
439 /* Create the display */
440 p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
441 p_vout->output.i_height, dd );
443 if(p_pic->p_sys->pQImage == NULL)
451 p_pic->p->i_pixel_pitch = 1;
455 p_pic->p->i_pixel_pitch = 2;
459 p_pic->p->i_pixel_pitch = 4;
465 p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
466 p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
467 p_pic->p->i_lines = p_vout->output.i_height;
468 p_pic->p->i_visible_lines = p_vout->output.i_height;
469 p_pic->p->i_visible_pitch =
470 p_pic->p->i_pixel_pitch * p_vout->output.i_width;
477 /*****************************************************************************
478 * FreePicture: destroy a picture allocated with NewPicture
479 *****************************************************************************/
480 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
482 delete p_pic->p_sys->pQImage;
485 /*****************************************************************************
486 * ToggleFullScreen: Enable or disable full screen mode
487 *****************************************************************************
488 * This function will switch between fullscreen and window mode.
490 *****************************************************************************/
491 static void ToggleFullScreen ( vout_thread_t *p_vout )
493 if ( p_vout->b_fullscreen )
494 p_vout->p_sys->p_VideoWidget->showFullScreen();
496 p_vout->p_sys->p_VideoWidget->showNormal();
498 p_vout->b_fullscreen = !p_vout->b_fullscreen;
501 /*****************************************************************************
502 * OpenDisplay: create qte applicaton / window
503 *****************************************************************************
504 * Create a window according to video output given size, and set other
505 * properties according to the display properties.
506 *****************************************************************************/
507 static int OpenDisplay( vout_thread_t *p_vout )
509 /* for displaying the vout in a qt window we need the QtApplication */
510 p_vout->p_sys->p_QApplication = NULL;
511 p_vout->p_sys->p_VideoWidget = NULL;
513 p_vout->p_sys->p_event = (event_thread_t*) vlc_object_create( p_vout, sizeof(event_thread_t) );
514 p_vout->p_sys->p_event->p_vout = p_vout;
516 /* Initializations */
517 #if 1 /* FIXME: I need an event queue to handle video output size changes. */
518 p_vout->b_fullscreen = true;
521 /* Set main window's size */
522 QWidget *desktop = p_vout->p_sys->p_QApplication->desktop();
523 p_vout->p_sys->i_width = p_vout->b_fullscreen ? desktop->height() :
524 p_vout->i_window_width;
525 p_vout->p_sys->i_height = p_vout->b_fullscreen ? desktop->width() :
526 p_vout->i_window_height;
528 #if 0 /* FIXME: I need an event queue to handle video output size changes. */
529 /* Update dimensions */
530 p_vout->i_changes |= VOUT_SIZE_CHANGE;
531 p_vout->i_window_width = p_vout->p_sys->i_width;
532 p_vout->i_window_height = p_vout->p_sys->i_height;
535 msg_Dbg( p_vout, "opening display (h=%d,w=%d)",p_vout->p_sys->i_height,p_vout->p_sys->i_width);
537 /* create thread to exec the qpe application */
538 if ( vlc_thread_create( p_vout->p_sys->p_event, "QT Embedded Thread",
540 VLC_THREAD_PRIORITY_OUTPUT, true) )
542 msg_Err( p_vout, "cannot create QT Embedded Thread" );
543 vlc_object_release( p_vout->p_sys->p_event );
544 p_vout->p_sys->p_event = NULL;
548 if( p_vout->p_sys->p_event->b_error )
550 msg_Err( p_vout, "RunQtThread failed" );
554 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
555 msg_Dbg( p_vout, "RunQtThread running" );
557 // just wait until the crew is complete...
558 while(p_vout->p_sys->p_VideoWidget == NULL)
566 /*****************************************************************************
567 * CloseDisplay: destroy the window
568 *****************************************************************************/
569 static void CloseDisplay( vout_thread_t *p_vout )
571 // quit qt application loop
572 msg_Dbg( p_vout, "destroying Qt Window" );
574 if(p_vout->p_sys->p_QApplication)
576 p_vout->p_sys->bRunning = FALSE;
577 while(p_vout->p_sys->p_VideoWidget)
583 if (p_vout->p_sys->p_QApplication)
584 p_vout->p_sys->p_QApplication->quit();
588 /*****************************************************************************
589 * main loop of qtapplication
590 *****************************************************************************/
591 static void* RunQtThread( vlc_object_t *p_this )
593 event_thread_t *p_event = (event_thread_t *)p_this;
594 int canc = vlc_savecancel ();
595 msg_Dbg( p_event->p_vout, "RunQtThread starting" );
600 p_event->p_vout->p_sys->p_QApplication = qApp;
601 p_event->p_vout->p_sys->bOwnsQApp = FALSE;
602 p_event->p_vout->p_sys->p_VideoWidget = qApp->mainWidget();
603 msg_Dbg( p_event->p_vout, "RunQtThread applicaton attached" );
609 QApplication* pApp = new QApplication(argc, NULL);
612 p_event->p_vout->p_sys->p_QApplication = pApp;
613 p_event->p_vout->p_sys->bOwnsQApp = TRUE;
615 QWidget* pWidget = new QWidget();
618 p_event->p_vout->p_sys->p_VideoWidget = pWidget;
622 /* signal the creation of the window */
623 vlc_thread_ready( p_event );
624 msg_Dbg( p_event->p_vout, "RunQtThread ready" );
626 if (p_event->p_vout->p_sys->p_QApplication)
628 /* Set default window width and heigh to exactly preferred size. */
629 QWidget *desktop = p_event->p_vout->p_sys->p_QApplication->desktop();
630 p_event->p_vout->p_sys->p_VideoWidget->setMinimumWidth( 10 );
631 p_event->p_vout->p_sys->p_VideoWidget->setMinimumHeight( 10 );
632 p_event->p_vout->p_sys->p_VideoWidget->setBaseSize( p_event->p_vout->p_sys->i_width,
633 p_event->p_vout->p_sys->i_height );
634 p_event->p_vout->p_sys->p_VideoWidget->setMaximumWidth( desktop->width() );
635 p_event->p_vout->p_sys->p_VideoWidget->setMaximumHeight( desktop->height() );
636 /* Check on fullscreen */
637 if (p_event->p_vout->b_fullscreen)
638 p_event->p_vout->p_sys->p_VideoWidget->showFullScreen();
640 p_event->p_vout->p_sys->p_VideoWidget->showNormal();
642 p_event->p_vout->p_sys->p_VideoWidget->show();
643 p_event->p_vout->p_sys->bRunning = TRUE;
646 while(vlc_object_alive (p_event) && p_event->p_vout->p_sys->bRunning)
648 /* Check if we are asked to exit */
649 if( !vlc_object_alive (p_event) )
655 // run the main loop of qtapplication until someone says: 'quit'
656 p_event->p_vout->p_sys->pcQApplication->exec();
660 #ifndef NEED_QTE_MAIN
661 if(p_event->p_vout->p_sys->p_QApplication)
663 delete p_event->p_vout->p_sys->p_VideoWidget;
664 p_event->p_vout->p_sys->p_VideoWidget = NULL;
665 delete p_event->p_vout->p_sys->p_QApplication;
666 p_event->p_vout->p_sys->p_QApplication = NULL;
669 p_event->p_vout->p_sys->p_VideoWidget = NULL;
672 msg_Dbg( p_event->p_vout, "RunQtThread terminating" );
673 vlc_restorecancel (canc);