]> git.sesse.net Git - vlc/blob - modules/video_output/qte/qte.cpp
b5619d57ec630f08f8a5f21d0ffc4ec033e555c5
[vlc] / modules / video_output / qte / qte.cpp
1 /*****************************************************************************
2  * qte.cpp : QT Embedded plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 1998-2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gerald Hansink <gerald.hansink@ordina.nl>
8  *          Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 /*****************************************************************************
30  * notes:
31  * - written for ipaq, so hardcoded assumptions specific for ipaq...
32  * - runs full screen
33  * - no "mouse events" handling
34  * - etc.
35  *****************************************************************************/
36
37 extern "C"
38 {
39 #include <errno.h>                                                 /* ENOMEM */
40
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44
45 #include <vlc_common.h>
46 #include <vlc_plugin.h>
47 #include <vlc_interface.h>
48 #include <vlc_vout.h>
49
50 #ifdef HAVE_MACHINE_PARAM_H
51     /* BSD */
52 #   include <machine/param.h>
53 #   include <sys/types.h>                                  /* typedef ushort */
54 #   include <sys/ipc.h>
55 #endif
56
57 #ifndef WIN32
58 #   include <netinet/in.h>                            /* BSD: struct in_addr */
59 #endif
60
61 #ifdef HAVE_SYS_SHM_H
62 #   include <sys/shm.h>                                /* shmget(), shmctl() */
63 #endif
64 } /* extern "C" */
65
66 #include <qapplication.h>
67 #include <qpainter.h>
68
69 #ifdef Q_WS_QWS
70 #   define USE_DIRECT_PAINTER
71 #   include <qdirectpainter_qws.h>
72 #   include <qgfxraster_qws.h>
73 #endif
74
75 extern "C"
76 {
77 #include "qte.h"
78
79 /*****************************************************************************
80  * Module descriptor
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.")
86
87 /*****************************************************************************
88  * Local prototypes
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 * );
97
98 static int  OpenDisplay ( vout_thread_t * );
99 static void CloseDisplay( vout_thread_t * );
100
101 static int  NewPicture     ( vout_thread_t *, picture_t * );
102 static void FreePicture    ( vout_thread_t *, picture_t * );
103
104 static void ToggleFullScreen      ( vout_thread_t * );
105
106 static void* RunQtThread( vlc_object_t *p_this );
107 } /* extern "C" */
108
109 /*****************************************************************************
110 * Exported prototypes
111 *****************************************************************************/
112 extern "C"
113 {
114
115 vlc_module_begin ()
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)
124 vlc_module_end ()
125
126 } /* extern "C" */
127
128 /*****************************************************************************
129  * Seeking function TODO: put this in a generic location !
130  *****************************************************************************/
131 static inline void vout_Seek( off_t i_seek )
132 {
133 }
134
135 /*****************************************************************************
136  * Open: allocate video thread output method
137  *****************************************************************************/
138 static int Open( vlc_object_t *p_this )
139 {
140     vout_thread_t * p_vout = (vout_thread_t *)p_this;
141
142     /* Allocate structure */
143     p_vout->p_sys = (struct vout_sys_t*) malloc( sizeof( struct vout_sys_t ) );
144
145     if( p_vout->p_sys == NULL )
146         return( 1 );
147
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;
153
154 #ifdef NEED_QTE_MAIN
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 )
158     {
159         free( p_vout->p_sys );
160         return VLC_ENOMOD;
161     }
162 #endif
163
164     if (OpenDisplay(p_vout))
165     {
166         msg_Err( p_vout, "Cannot set up qte video output" );
167         Close(p_this);
168         return( -1 );
169     }
170     return( 0 );
171 }
172
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 )
179 {
180     vout_thread_t * p_vout = (vout_thread_t *)p_this;
181
182     msg_Dbg( p_vout, "close" );
183     if( p_vout->p_sys->p_event )
184     {
185         vlc_object_detach( p_vout->p_sys->p_event );
186
187         /* Kill RunQtThread */
188         vlc_object_kill( p_vout->p_sys->p_event );
189         CloseDisplay(p_vout);
190
191         vlc_thread_join( p_vout->p_sys->p_event );
192         vlc_object_release( p_vout->p_sys->p_event );
193     }
194
195 #ifdef NEED_QTE_MAIN
196     msg_Dbg( p_vout, "releasing gui-helper" );
197     module_unneed( p_vout, p_vout->p_sys->p_qte_main );
198 #endif
199
200     free( p_vout->p_sys );
201     p_vout->p_sys = NULL;
202 }
203
204 /*****************************************************************************
205  * Init: initialize video thread output method
206  *****************************************************************************
207  * This function create the buffers needed by the output thread. It is called
208  * at the beginning of the thread, but also each time the window is resized.
209  *****************************************************************************/
210 static int Init( vout_thread_t *p_vout )
211 {
212     int         i_index;
213     picture_t*  p_pic;
214     int         dd = QPixmap::defaultDepth();
215
216     I_OUTPUTPICTURES = 0;
217
218     p_vout->output.i_chroma = (dd == 16) ? VLC_CODEC_RGB16 : VLC_CODEC_RGB32;
219     p_vout->output.i_rmask  = 0xf800;
220     p_vout->output.i_gmask  = 0x07e0;
221     p_vout->output.i_bmask  = 0x001f;
222
223     /* All we have is an RGB image with square pixels */
224     p_vout->output.i_width  = p_vout->p_sys->i_width;
225     p_vout->output.i_height = p_vout->p_sys->i_height;
226     if( !p_vout->b_fullscreen )
227     {
228         p_vout->output.i_aspect = p_vout->output.i_width
229                                    * VOUT_ASPECT_FACTOR
230                                    / p_vout->output.i_height;
231     }
232     else
233     {
234         p_vout->output.i_aspect = p_vout->render.i_aspect;
235     }
236 #if 0
237     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 );
238 #endif
239     /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
240     while( I_OUTPUTPICTURES < QTE_MAX_DIRECTBUFFERS )
241     {
242         p_pic = NULL;
243
244         /* Find an empty picture slot */
245         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
246         {
247             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
248             {
249                 p_pic = p_vout->p_picture + i_index;
250                 break;
251             }
252         }
253
254         /* Allocate the picture */
255         if( p_pic == NULL ||  NewPicture( p_vout, p_pic ) )
256         {
257             break;
258         }
259
260         p_pic->i_status = DESTROYED_PICTURE;
261         p_pic->i_type   = DIRECT_PICTURE;
262
263         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
264
265         I_OUTPUTPICTURES++;
266     }
267
268     return( 0 );
269 }
270
271
272 /*****************************************************************************
273  * Render: render previously calculated output
274  *****************************************************************************/
275 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
276 {
277     ;
278 }
279
280 /*****************************************************************************
281  * Display: displays previously rendered output
282  *****************************************************************************
283  * This function sends the currently rendered image to screen.
284  *****************************************************************************/
285 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
286 {
287     unsigned int x, y, w, h;
288
289     vout_PlacePicture( p_vout, p_vout->output.i_width, p_vout->output.i_height,
290                        &x, &y, &w, &h );
291 #if 0
292     msg_Dbg(p_vout, "+qte::Display( p_vout, i_width=%d, i_height=%d, x=%u, y=%u, w=%u, h=%u",
293         p_vout->output.i_width, p_vout->output.i_height, x, y, w, h );
294 #endif
295
296     if(p_vout->p_sys->p_VideoWidget)
297     {
298 // shameless borrowed from opie mediaplayer....
299 #ifndef USE_DIRECT_PAINTER
300         msg_Dbg(p_vout, "not using direct painter");
301         QPainter p(p_vout->p_sys->p_VideoWidget);
302
303         /* rotate frame */
304         int dd      = QPixmap::defaultDepth();
305         int bytes   = ( dd == 16 ) ? 2 : 4;
306         int rw = h, rh = w;
307
308         QImage rotatedFrame( rw, rh, bytes << 3 );
309
310         ushort* in  = (ushort*)p_pic->p_sys->pQImage->bits();
311         ushort* out = (ushort*)rotatedFrame.bits();
312
313         int spl = rotatedFrame.bytesPerLine() / bytes;
314         for (int x=0; x<h; x++)
315         {
316             if ( bytes == 2 )
317             {
318                 ushort* lout = out++ + (w - 1)*spl;
319                 for (int y=0; y<w; y++)
320                 {
321                     *lout=*in++;
322                     lout-=spl;
323                 }
324             }
325             else
326             {
327                 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
328                 for (int y=0; y<w; y++)
329                 {
330                     *lout=*((ulong*)in)++;
331                     lout-=spl;
332                 }
333             }
334         }
335
336         p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh );
337 #else
338         QDirectPainter p(p_vout->p_sys->p_VideoWidget);
339         p.transformOrientation();
340         // just copy the image to the frame buffer...
341         memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep());
342 #endif
343     }
344 }
345
346 /*****************************************************************************
347  * Manage: handle Qte events
348  *****************************************************************************
349  * This function should be called regularly by video output thread. It manages
350  * Qte events and allows window resizing. It returns a non null value on
351  * error.
352  *****************************************************************************/
353 static int Manage( vout_thread_t *p_vout )
354 {
355 //    msg_Dbg( p_vout, "Manage" );
356
357     /* Fullscreen change */
358     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
359     {
360         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
361
362 //        p_vout->p_sys->b_cursor_autohidden = 0;
363 //        SDL_ShowCursor( p_vout->p_sys->b_cursor &&
364 //                        ! p_vout->p_sys->b_cursor_autohidden );
365
366         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
367         p_vout->i_changes |= VOUT_SIZE_CHANGE;
368     }
369
370     /*
371      * Size change
372      */
373     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
374     {
375         msg_Dbg( p_vout, "video display resized (%dx%d)",
376                  p_vout->p_sys->i_width, p_vout->p_sys->i_height );
377
378         CloseDisplay( p_vout );
379         OpenDisplay( p_vout );
380
381         /* We don't need to signal the vout thread about the size change if
382          * we can handle rescaling ourselves */
383         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
384     }
385
386     /* Pointer change */
387 //    if( ! p_vout->p_sys->b_cursor_autohidden &&
388 //        ( mdate() - p_vout->p_sys->i_lastmoved >
389 //            p_vout->p_sys->i_mouse_hide_timeout ) )
390 //    {
391 //        /* Hide the mouse automatically */
392 //        p_vout->p_sys->b_cursor_autohidden = 1;
393 //        SDL_ShowCursor( 0 );
394 //    }
395 //
396 //    if( !vlc_object_alive (p_vout->p_libvlc) )
397 //        p_vout->p_sys->bRunning = FALSE;
398
399     return 0;
400 }
401
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 )
409 {
410     int i_index;
411
412     /* Free the direct buffers we allocated */
413     for( i_index = I_OUTPUTPICTURES ; i_index ; )
414     {
415         i_index--;
416         FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
417     }
418 }
419
420
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 )
427 {
428     int dd = QPixmap::defaultDepth();
429
430     p_pic->p_sys = (picture_sys_t*) malloc( sizeof( picture_sys_t ) );
431     if( p_pic->p_sys == NULL )
432     {
433         return -1;
434     }
435
436     /* Create the display */
437     p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
438                                        p_vout->output.i_height, dd );
439
440     if(p_pic->p_sys->pQImage == NULL)
441     {
442         return -1;
443     }
444
445     switch( dd )
446     {
447         case 8:
448             p_pic->p->i_pixel_pitch = 1;
449             break;
450         case 15:
451         case 16:
452             p_pic->p->i_pixel_pitch = 2;
453             break;
454         case 24:
455         case 32:
456             p_pic->p->i_pixel_pitch = 4;
457             break;
458         default:
459             return( -1 );
460     }
461
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_lines = p_vout->output.i_height;
466     p_pic->p->i_visible_pitch =
467             p_pic->p->i_pixel_pitch * p_vout->output.i_width;
468
469     p_pic->i_planes = 1;
470
471     return 0;
472 }
473
474 /*****************************************************************************
475  * FreePicture: destroy a picture allocated with NewPicture
476  *****************************************************************************/
477 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
478 {
479     delete p_pic->p_sys->pQImage;
480 }
481
482 /*****************************************************************************
483  * ToggleFullScreen: Enable or disable full screen mode
484  *****************************************************************************
485  * This function will switch between fullscreen and window mode.
486  *
487  *****************************************************************************/
488 static void ToggleFullScreen ( vout_thread_t *p_vout )
489 {
490     if ( p_vout->b_fullscreen )
491        p_vout->p_sys->p_VideoWidget->showFullScreen();
492     else
493        p_vout->p_sys->p_VideoWidget->showNormal();
494
495     p_vout->b_fullscreen = !p_vout->b_fullscreen;
496 }
497
498 /*****************************************************************************
499  * OpenDisplay: create qte applicaton / window
500  *****************************************************************************
501  * Create a window according to video output given size, and set other
502  * properties according to the display properties.
503  *****************************************************************************/
504 static int OpenDisplay( vout_thread_t *p_vout )
505 {
506     /* for displaying the vout in a qt window we need the QtApplication */
507     p_vout->p_sys->p_QApplication = NULL;
508     p_vout->p_sys->p_VideoWidget = NULL;
509
510     p_vout->p_sys->p_event = (event_thread_t*) vlc_object_create( p_vout, sizeof(event_thread_t) );
511     p_vout->p_sys->p_event->p_vout = p_vout;
512
513     /* Initializations */
514 #if 1 /* FIXME: I need an event queue to handle video output size changes. */
515     p_vout->b_fullscreen = true;
516 #endif
517
518     /* Set main window's size */
519     QWidget *desktop = p_vout->p_sys->p_QApplication->desktop();
520     p_vout->p_sys->i_width = p_vout->b_fullscreen ? desktop->height() :
521                                                     p_vout->i_window_width;
522     p_vout->p_sys->i_height = p_vout->b_fullscreen ? desktop->width() :
523                                                      p_vout->i_window_height;
524
525 #if 0 /* FIXME: I need an event queue to handle video output size changes. */
526     /* Update dimensions */
527     p_vout->i_changes |= VOUT_SIZE_CHANGE;
528     p_vout->i_window_width = p_vout->p_sys->i_width;
529     p_vout->i_window_height = p_vout->p_sys->i_height;
530 #endif
531
532     msg_Dbg( p_vout, "opening display (h=%d,w=%d)",p_vout->p_sys->i_height,p_vout->p_sys->i_width);
533
534     /* create thread to exec the qpe application */
535     if ( vlc_thread_create( p_vout->p_sys->p_event, "QT Embedded Thread",
536                             RunQtThread,
537                             VLC_THREAD_PRIORITY_OUTPUT, true) )
538     {
539         msg_Err( p_vout, "cannot create QT Embedded Thread" );
540         vlc_object_release( p_vout->p_sys->p_event );
541         p_vout->p_sys->p_event = NULL;
542         return -1;
543     }
544
545     if( p_vout->p_sys->p_event->b_error )
546     {
547         msg_Err( p_vout, "RunQtThread failed" );
548         return -1;
549     }
550
551     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
552     msg_Dbg( p_vout, "RunQtThread running" );
553
554     // just wait until the crew is complete...
555     while(p_vout->p_sys->p_VideoWidget == NULL)
556     {
557         msleep(1);
558     }
559     return VLC_SUCCESS;
560 }
561
562
563 /*****************************************************************************
564  * CloseDisplay: destroy the window
565  *****************************************************************************/
566 static void CloseDisplay( vout_thread_t *p_vout )
567 {
568     // quit qt application loop
569     msg_Dbg( p_vout, "destroying Qt Window" );
570 #ifdef NEED_QTE_MAIN
571     if(p_vout->p_sys->p_QApplication)
572     {
573         p_vout->p_sys->bRunning = FALSE;
574         while(p_vout->p_sys->p_VideoWidget)
575         {
576             msleep(1);
577         }
578     }
579 #else
580     if (p_vout->p_sys->p_QApplication)
581        p_vout->p_sys->p_QApplication->quit();
582 #endif
583 }
584
585 /*****************************************************************************
586  * main loop of qtapplication
587  *****************************************************************************/
588 static void* RunQtThread( vlc_object_t *p_this )
589 {
590     event_thread_t *p_event = (event_thread_t *)p_this;
591     int canc = vlc_savecancel ();
592     msg_Dbg( p_event->p_vout, "RunQtThread starting" );
593
594 #ifdef NEED_QTE_MAIN
595     if (qApp)
596     {
597         p_event->p_vout->p_sys->p_QApplication = qApp;
598         p_event->p_vout->p_sys->bOwnsQApp = FALSE;
599         p_event->p_vout->p_sys->p_VideoWidget = qApp->mainWidget();
600         msg_Dbg( p_event->p_vout, "RunQtThread applicaton attached" );
601     }
602 #else
603     if (qApp==NULL)
604     {
605         int argc = 0;
606         QApplication* pApp = new QApplication(argc, NULL);
607         if(pApp)
608         {
609             p_event->p_vout->p_sys->p_QApplication = pApp;
610             p_event->p_vout->p_sys->bOwnsQApp = TRUE;
611         }
612         QWidget* pWidget = new QWidget();
613         if (pWidget)
614             {
615             p_event->p_vout->p_sys->p_VideoWidget = pWidget;
616         }
617     }
618 #endif
619     /* signal the creation of the window */
620     vlc_thread_ready( p_event );
621     msg_Dbg( p_event->p_vout, "RunQtThread ready" );
622
623     if (p_event->p_vout->p_sys->p_QApplication)
624     {
625         /* Set default window width and heigh to exactly preferred size. */
626             QWidget *desktop = p_event->p_vout->p_sys->p_QApplication->desktop();
627             p_event->p_vout->p_sys->p_VideoWidget->setMinimumWidth( 10 );
628              p_event->p_vout->p_sys->p_VideoWidget->setMinimumHeight( 10 );
629             p_event->p_vout->p_sys->p_VideoWidget->setBaseSize( p_event->p_vout->p_sys->i_width,
630             p_event->p_vout->p_sys->i_height );
631         p_event->p_vout->p_sys->p_VideoWidget->setMaximumWidth( desktop->width() );
632         p_event->p_vout->p_sys->p_VideoWidget->setMaximumHeight( desktop->height() );
633         /* Check on fullscreen */
634         if (p_event->p_vout->b_fullscreen)
635                   p_event->p_vout->p_sys->p_VideoWidget->showFullScreen();
636         else
637                 p_event->p_vout->p_sys->p_VideoWidget->showNormal();
638
639         p_event->p_vout->p_sys->p_VideoWidget->show();
640         p_event->p_vout->p_sys->bRunning = TRUE;
641
642 #ifdef NEED_QTE_MAIN
643         while(vlc_object_alive (p_event) && p_event->p_vout->p_sys->bRunning)
644               {
645                /* Check if we are asked to exit */
646            if( !vlc_object_alive (p_event) )
647                break;
648
649                msleep(100);
650             }
651 #else
652         // run the main loop of qtapplication until someone says: 'quit'
653         p_event->p_vout->p_sys->pcQApplication->exec();
654 #endif
655     }
656
657 #ifndef NEED_QTE_MAIN
658     if(p_event->p_vout->p_sys->p_QApplication)
659     {
660         delete p_event->p_vout->p_sys->p_VideoWidget;
661         p_event->p_vout->p_sys->p_VideoWidget = NULL;
662         delete p_event->p_vout->p_sys->p_QApplication;
663         p_event->p_vout->p_sys->p_QApplication = NULL;
664     }
665 #else
666     p_event->p_vout->p_sys->p_VideoWidget = NULL;
667 #endif
668
669     msg_Dbg( p_event->p_vout, "RunQtThread terminating" );
670     vlc_restorecancel (canc);
671     return NULL;
672 }
673