]> git.sesse.net Git - vlc/blob - modules/video_output/qte/qte.cpp
Use gettext_noop() consistently
[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/vlc.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( event_thread_t *p_event );
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     {
147         msg_Err( p_vout, "out of memory" );
148         return( 1 );
149     }
150
151     p_vout->pf_init    = Init;
152     p_vout->pf_end     = End;
153     p_vout->pf_manage  = Manage;
154     p_vout->pf_render  = NULL; //Render;
155     p_vout->pf_display = Display;
156
157 #ifdef NEED_QTE_MAIN
158     p_vout->p_sys->p_qte_main =
159         module_Need( p_this, "gui-helper", "qte", true );
160     if( p_vout->p_sys->p_qte_main == NULL )
161     {
162         free( p_vout->p_sys );
163         return VLC_ENOMOD;
164     }
165 #endif
166
167     if (OpenDisplay(p_vout))
168     {
169         msg_Err( p_vout, "Cannot set up qte video output" );
170         Close(p_this);
171         return( -1 );
172     }
173     return( 0 );
174 }
175
176 /*****************************************************************************
177  * CloseVideo: destroy Sys video thread output method
178  *****************************************************************************
179  * Terminate an output method created by Open
180  *****************************************************************************/
181 static void Close ( vlc_object_t *p_this )
182 {
183     vout_thread_t * p_vout = (vout_thread_t *)p_this;
184
185     msg_Dbg( p_vout, "close" );
186     if( p_vout->p_sys->p_event )
187     {
188         vlc_object_detach( p_vout->p_sys->p_event );
189
190         /* Kill RunQtThread */
191         vlc_object_kill( p_vout->p_sys->p_event );
192         CloseDisplay(p_vout);
193
194         vlc_thread_join( p_vout->p_sys->p_event );
195         vlc_object_release( p_vout->p_sys->p_event );
196     }
197
198 #ifdef NEED_QTE_MAIN
199     msg_Dbg( p_vout, "releasing gui-helper" );
200     module_Unneed( p_vout, p_vout->p_sys->p_qte_main );
201 #endif
202
203     if( p_vout->p_sys )
204     {
205         free( p_vout->p_sys );
206         p_vout->p_sys = NULL;
207     }
208 }
209
210 /*****************************************************************************
211  * Init: initialize video thread output method
212  *****************************************************************************
213  * This function create the buffers needed by the output thread. It is called
214  * at the beginning of the thread, but also each time the window is resized.
215  *****************************************************************************/
216 static int Init( vout_thread_t *p_vout )
217 {
218     int         i_index;
219     picture_t*  p_pic;
220     int         dd = QPixmap::defaultDepth();
221
222     I_OUTPUTPICTURES = 0;
223
224     p_vout->output.i_chroma = (dd == 16) ? VLC_FOURCC('R','V','1','6'): VLC_FOURCC('R','V','3','2');
225     p_vout->output.i_rmask  = 0xf800;
226     p_vout->output.i_gmask  = 0x07e0;
227     p_vout->output.i_bmask  = 0x001f;
228
229     /* All we have is an RGB image with square pixels */
230     p_vout->output.i_width  = p_vout->p_sys->i_width;
231     p_vout->output.i_height = p_vout->p_sys->i_height;
232     if( !p_vout->b_fullscreen )
233     {
234         p_vout->output.i_aspect = p_vout->output.i_width
235                                    * VOUT_ASPECT_FACTOR
236                                    / p_vout->output.i_height;
237     }
238     else
239     {
240         p_vout->output.i_aspect = p_vout->render.i_aspect;
241     }
242 #if 0
243     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 );
244 #endif
245     /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
246     while( I_OUTPUTPICTURES < QTE_MAX_DIRECTBUFFERS )
247     {
248         p_pic = NULL;
249
250         /* Find an empty picture slot */
251         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
252         {
253             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
254             {
255                 p_pic = p_vout->p_picture + i_index;
256                 break;
257             }
258         }
259
260         /* Allocate the picture */
261         if( p_pic == NULL ||  NewPicture( p_vout, p_pic ) )
262         {
263             break;
264         }
265
266         p_pic->i_status = DESTROYED_PICTURE;
267         p_pic->i_type   = DIRECT_PICTURE;
268
269         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
270
271         I_OUTPUTPICTURES++;
272     }
273
274     return( 0 );
275 }
276
277
278 /*****************************************************************************
279  * Render: render previously calculated output
280  *****************************************************************************/
281 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
282 {
283     ;
284 }
285
286 /*****************************************************************************
287  * Display: displays previously rendered output
288  *****************************************************************************
289  * This function sends the currently rendered image to screen.
290  *****************************************************************************/
291 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
292 {
293     unsigned int x, y, w, h;
294
295     vout_PlacePicture( p_vout, p_vout->output.i_width, p_vout->output.i_height,
296                        &x, &y, &w, &h );
297 #if 0
298     msg_Dbg(p_vout, "+qte::Display( p_vout, i_width=%d, i_height=%d, x=%u, y=%u, w=%u, h=%u",
299         p_vout->output.i_width, p_vout->output.i_height, x, y, w, h );
300 #endif
301
302     if(p_vout->p_sys->p_VideoWidget)
303     {
304 // shameless borrowed from opie mediaplayer....
305 #ifndef USE_DIRECT_PAINTER
306         msg_Dbg(p_vout, "not using direct painter");
307         QPainter p(p_vout->p_sys->p_VideoWidget);
308
309         /* rotate frame */
310         int dd      = QPixmap::defaultDepth();
311         int bytes   = ( dd == 16 ) ? 2 : 4;
312         int rw = h, rh = w;
313
314         QImage rotatedFrame( rw, rh, bytes << 3 );
315
316         ushort* in  = (ushort*)p_pic->p_sys->pQImage->bits();
317         ushort* out = (ushort*)rotatedFrame.bits();
318
319         int spl = rotatedFrame.bytesPerLine() / bytes;
320         for (int x=0; x<h; x++)
321         {
322             if ( bytes == 2 )
323             {
324                 ushort* lout = out++ + (w - 1)*spl;
325                 for (int y=0; y<w; y++)
326                 {
327                     *lout=*in++;
328                     lout-=spl;
329                 }
330             }
331             else
332             {
333                 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
334                 for (int y=0; y<w; y++)
335                 {
336                     *lout=*((ulong*)in)++;
337                     lout-=spl;
338                 }
339             }
340         }
341
342         p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh );
343 #else
344         QDirectPainter p(p_vout->p_sys->p_VideoWidget);
345         p.transformOrientation();
346         // just copy the image to the frame buffer...
347         memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep());
348 #endif
349     }
350 }
351
352 /*****************************************************************************
353  * Manage: handle Qte events
354  *****************************************************************************
355  * This function should be called regularly by video output thread. It manages
356  * Qte events and allows window resizing. It returns a non null value on
357  * error.
358  *****************************************************************************/
359 static int Manage( vout_thread_t *p_vout )
360 {
361 //    msg_Dbg( p_vout, "Manage" );
362
363     /* Fullscreen change */
364     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
365     {
366         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
367
368 //        p_vout->p_sys->b_cursor_autohidden = 0;
369 //        SDL_ShowCursor( p_vout->p_sys->b_cursor &&
370 //                        ! p_vout->p_sys->b_cursor_autohidden );
371
372         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
373         p_vout->i_changes |= VOUT_SIZE_CHANGE;
374     }
375
376     /*
377      * Size change
378      */
379     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
380     {
381         msg_Dbg( p_vout, "video display resized (%dx%d)",
382                  p_vout->p_sys->i_width, p_vout->p_sys->i_height );
383
384         CloseDisplay( p_vout );
385         OpenDisplay( p_vout );
386
387         /* We don't need to signal the vout thread about the size change if
388          * we can handle rescaling ourselves */
389         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
390     }
391
392     /* Pointer change */
393 //    if( ! p_vout->p_sys->b_cursor_autohidden &&
394 //        ( mdate() - p_vout->p_sys->i_lastmoved >
395 //            p_vout->p_sys->i_mouse_hide_timeout ) )
396 //    {
397 //        /* Hide the mouse automatically */
398 //        p_vout->p_sys->b_cursor_autohidden = 1;
399 //        SDL_ShowCursor( 0 );
400 //    }
401 //
402 //    if( p_vout->p_libvlc->b_die )
403 //        p_vout->p_sys->bRunning = FALSE;
404
405     return 0;
406 }
407
408 /*****************************************************************************
409  * End: terminate video thread output method
410  *****************************************************************************
411  * Destroy the buffers created by vout_Init. It is called at the end of
412  * the thread, but also each time the window is resized.
413  *****************************************************************************/
414 static void End( vout_thread_t *p_vout )
415 {
416     int i_index;
417
418     /* Free the direct buffers we allocated */
419     for( i_index = I_OUTPUTPICTURES ; i_index ; )
420     {
421         i_index--;
422         FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
423     }
424 }
425
426
427 /*****************************************************************************
428  * NewPicture: allocate a picture
429  *****************************************************************************
430  * Returns 0 on success, -1 otherwise
431  *****************************************************************************/
432 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
433 {
434     int dd = QPixmap::defaultDepth();
435
436     p_pic->p_sys = (picture_sys_t*) malloc( sizeof( picture_sys_t ) );
437     if( p_pic->p_sys == NULL )
438     {
439         return -1;
440     }
441
442     /* Create the display */
443     p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
444                                        p_vout->output.i_height, dd );
445
446     if(p_pic->p_sys->pQImage == NULL)
447     {
448         return -1;
449     }
450
451     switch( dd )
452     {
453         case 8:
454             p_pic->p->i_pixel_pitch = 1;
455             break;
456         case 15:
457         case 16:
458             p_pic->p->i_pixel_pitch = 2;
459             break;
460         case 24:
461         case 32:
462             p_pic->p->i_pixel_pitch = 4;
463             break;
464         default:
465             return( -1 );
466     }
467
468     p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
469     p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
470     p_pic->p->i_lines = p_vout->output.i_height;
471     p_pic->p->i_visible_lines = p_vout->output.i_height;
472     p_pic->p->i_visible_pitch =
473             p_pic->p->i_pixel_pitch * p_vout->output.i_width;
474
475     p_pic->i_planes = 1;
476
477     return 0;
478 }
479
480 /*****************************************************************************
481  * FreePicture: destroy a picture allocated with NewPicture
482  *****************************************************************************/
483 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
484 {
485     delete p_pic->p_sys->pQImage;
486 }
487
488 /*****************************************************************************
489  * ToggleFullScreen: Enable or disable full screen mode
490  *****************************************************************************
491  * This function will switch between fullscreen and window mode.
492  *
493  *****************************************************************************/
494 static void ToggleFullScreen ( vout_thread_t *p_vout )
495 {
496     if ( p_vout->b_fullscreen )
497        p_vout->p_sys->p_VideoWidget->showFullScreen();
498     else
499        p_vout->p_sys->p_VideoWidget->showNormal();
500
501     p_vout->b_fullscreen = !p_vout->b_fullscreen;
502 }
503
504 /*****************************************************************************
505  * OpenDisplay: create qte applicaton / window
506  *****************************************************************************
507  * Create a window according to video output given size, and set other
508  * properties according to the display properties.
509  *****************************************************************************/
510 static int OpenDisplay( vout_thread_t *p_vout )
511 {
512     /* for displaying the vout in a qt window we need the QtApplication */
513     p_vout->p_sys->p_QApplication = NULL;
514     p_vout->p_sys->p_VideoWidget = NULL;
515
516     p_vout->p_sys->p_event = (event_thread_t*) vlc_object_create( p_vout, sizeof(event_thread_t) );
517     p_vout->p_sys->p_event->p_vout = p_vout;
518
519     /* Initializations */
520 #if 1 /* FIXME: I need an event queue to handle video output size changes. */
521     p_vout->b_fullscreen = true;
522 #endif
523
524     /* Set main window's size */
525     QWidget *desktop = p_vout->p_sys->p_QApplication->desktop();
526     p_vout->p_sys->i_width = p_vout->b_fullscreen ? desktop->height() :
527                                                     p_vout->i_window_width;
528     p_vout->p_sys->i_height = p_vout->b_fullscreen ? desktop->width() :
529                                                      p_vout->i_window_height;
530
531 #if 0 /* FIXME: I need an event queue to handle video output size changes. */
532     /* Update dimensions */
533     p_vout->i_changes |= VOUT_SIZE_CHANGE;
534     p_vout->i_window_width = p_vout->p_sys->i_width;
535     p_vout->i_window_height = p_vout->p_sys->i_height;
536 #endif
537
538     msg_Dbg( p_vout, "opening display (h=%d,w=%d)",p_vout->p_sys->i_height,p_vout->p_sys->i_width);
539
540     /* create thread to exec the qpe application */
541     if ( vlc_thread_create( p_vout->p_sys->p_event, "QT Embedded Thread",
542                             RunQtThread,
543                             VLC_THREAD_PRIORITY_OUTPUT, true) )
544     {
545         msg_Err( p_vout, "cannot create QT Embedded Thread" );
546         vlc_object_release( p_vout->p_sys->p_event );
547         p_vout->p_sys->p_event = NULL;
548         return -1;
549     }
550
551     if( p_vout->p_sys->p_event->b_error )
552     {
553         msg_Err( p_vout, "RunQtThread failed" );
554         return -1;
555     }
556
557     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
558     msg_Dbg( p_vout, "RunQtThread running" );
559
560     // just wait until the crew is complete...
561     while(p_vout->p_sys->p_VideoWidget == NULL)
562     {
563         msleep(1);
564     }
565     return VLC_SUCCESS;
566 }
567
568
569 /*****************************************************************************
570  * CloseDisplay: destroy the window
571  *****************************************************************************/
572 static void CloseDisplay( vout_thread_t *p_vout )
573 {
574     // quit qt application loop
575     msg_Dbg( p_vout, "destroying Qt Window" );
576 #ifdef NEED_QTE_MAIN
577     if(p_vout->p_sys->p_QApplication)
578     {
579         p_vout->p_sys->bRunning = FALSE;
580         while(p_vout->p_sys->p_VideoWidget)
581         {
582             msleep(1);
583         }
584     }
585 #else
586     if (p_vout->p_sys->p_QApplication)
587        p_vout->p_sys->p_QApplication->quit();
588 #endif
589 }
590
591 /*****************************************************************************
592  * main loop of qtapplication
593  *****************************************************************************/
594 static void RunQtThread(event_thread_t *p_event)
595 {
596     msg_Dbg( p_event->p_vout, "RunQtThread starting" );
597
598 #ifdef NEED_QTE_MAIN
599     if (qApp)
600     {
601         p_event->p_vout->p_sys->p_QApplication = qApp;
602         p_event->p_vout->p_sys->bOwnsQApp = FALSE;
603         p_event->p_vout->p_sys->p_VideoWidget = qApp->mainWidget();
604         msg_Dbg( p_event->p_vout, "RunQtThread applicaton attached" );
605     }
606 #else
607     if (qApp==NULL)
608     {
609         int argc = 0;
610         QApplication* pApp = new QApplication(argc, NULL);
611         if(pApp)
612         {
613             p_event->p_vout->p_sys->p_QApplication = pApp;
614             p_event->p_vout->p_sys->bOwnsQApp = TRUE;
615         }
616         QWidget* pWidget = new QWidget();
617         if (pWidget)
618             {
619             p_event->p_vout->p_sys->p_VideoWidget = pWidget;
620         }
621     }
622 #endif
623     /* signal the creation of the window */
624     vlc_thread_ready( p_event );
625     msg_Dbg( p_event->p_vout, "RunQtThread ready" );
626
627     if (p_event->p_vout->p_sys->p_QApplication)
628     {
629         /* Set default window width and heigh to exactly preferred size. */
630             QWidget *desktop = p_event->p_vout->p_sys->p_QApplication->desktop();
631             p_event->p_vout->p_sys->p_VideoWidget->setMinimumWidth( 10 );
632              p_event->p_vout->p_sys->p_VideoWidget->setMinimumHeight( 10 );
633             p_event->p_vout->p_sys->p_VideoWidget->setBaseSize( p_event->p_vout->p_sys->i_width,
634             p_event->p_vout->p_sys->i_height );
635         p_event->p_vout->p_sys->p_VideoWidget->setMaximumWidth( desktop->width() );
636         p_event->p_vout->p_sys->p_VideoWidget->setMaximumHeight( desktop->height() );
637         /* Check on fullscreen */
638         if (p_event->p_vout->b_fullscreen)
639                   p_event->p_vout->p_sys->p_VideoWidget->showFullScreen();
640         else
641                 p_event->p_vout->p_sys->p_VideoWidget->showNormal();
642
643         p_event->p_vout->p_sys->p_VideoWidget->show();
644         p_event->p_vout->p_sys->bRunning = TRUE;
645
646 #ifdef NEED_QTE_MAIN
647         while(!p_event->b_die && p_event->p_vout->p_sys->bRunning)
648               {
649                /* Check if we are asked to exit */
650            if( p_event->b_die )
651                break;
652
653                msleep(100);
654             }
655 #else
656         // run the main loop of qtapplication until someone says: 'quit'
657         p_event->p_vout->p_sys->pcQApplication->exec();
658 #endif
659     }
660
661 #ifndef NEED_QTE_MAIN
662     if(p_event->p_vout->p_sys->p_QApplication)
663     {
664         delete p_event->p_vout->p_sys->p_VideoWidget;
665         p_event->p_vout->p_sys->p_VideoWidget = NULL;
666         delete p_event->p_vout->p_sys->p_QApplication;
667         p_event->p_vout->p_sys->p_QApplication = NULL;
668     }
669 #else
670     p_event->p_vout->p_sys->p_VideoWidget = NULL;
671 #endif
672
673     msg_Dbg( p_event->p_vout, "RunQtThread terminating" );
674 }
675