]> git.sesse.net Git - vlc/blob - plugins/qte/vout_qte.cpp
d1a5227b93b702d2b13a0fbfa907bfd369f6e7b6
[vlc] / plugins / qte / vout_qte.cpp
1 /*****************************************************************************
2  * vout_qte.cpp : Qt Embedded video output plugin implementation
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: vout_qte.cpp,v 1.1.2.1 2002/11/26 19:54:12 jpsaman Exp $
6  *
7  * Authors: Gerald Hansink <gerald.hansink@ordina.nl>
8  *          Jean-Paul Saman <jpsaman@wxs.nl>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * notes:
27  * - written for ipaq, so hardcoded assumptions specific for ipaq...
28  * - runs full screen
29  * - no "mouse events" handling
30  * - etc.
31  *****************************************************************************/
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36 extern "C"
37 {
38 #include <errno.h>                                            /* ENOMEM */
39 #include <stdlib.h>                                           /* free() */
40 #include <string.h>                                           /* strerror() */
41
42 #include <videolan/vlc.h>
43
44 #ifdef HAVE_MACHINE_PARAM_H
45     /* BSD */
46 #   include <machine/param.h>
47 #   include <sys/types.h>                                  /* typedef ushort */
48 #   include <sys/ipc.h>
49 #endif
50
51 #ifndef WIN32
52 #   include <netinet/in.h>                            /* BSD: struct in_addr */
53 #endif
54
55 #ifdef HAVE_SYS_SHM_H
56 #   include <sys/shm.h>                                /* shmget(), shmctl() */
57 #endif
58
59 #include "video.h"
60 #include "video_output.h"
61
62 #include "interface.h"
63 #include "netutils.h"                                 /* network_ChannelJoin */
64
65 #include "stream_control.h"                 /* needed by input_ext-intf.h... */
66 #include "input_ext-intf.h"
67 } /* extern "C" */
68
69 /* QT Embedded include files */
70 #include <qapplication.h>
71 #include <qpainter.h>
72
73 #ifdef Q_WS_QWS
74 # define USE_DIRECT_PAINTER
75 # include <qdirectpainter_qws.h>
76 # include <qgfxraster_qws.h>
77 #endif
78
79 /*****************************************************************************
80  *  * Chroma defines
81  *****************************************************************************/
82 #define QTE_MAX_DIRECTBUFFERS    2
83
84 /*****************************************************************************
85  * Local prototypes
86  *****************************************************************************/
87 extern "C"
88 {
89 static int  vout_Create    ( vout_thread_t * );
90 static void vout_Destroy   ( vout_thread_t * );
91 static void vout_Render    ( vout_thread_t *, picture_t * );
92 static void vout_Display   ( vout_thread_t *, picture_t * );
93 static int  vout_Manage    ( vout_thread_t * );
94 static int  vout_Init      ( vout_thread_t * );
95 static void vout_End       ( vout_thread_t * );
96
97 static int  CreateQtWindow ( vout_thread_t * );
98 static void DestroyQtWindow( vout_thread_t * );
99
100 static int  NewPicture     ( vout_thread_t *, picture_t * );
101 static void FreePicture    ( vout_thread_t *, picture_t * );
102
103 static void ToggleFullScreen      ( vout_thread_t * );
104 } /* extern "C" */
105
106 static void* vout_run_qtapp_exec (void* pVoid);
107
108 /*****************************************************************************
109  * vout_sys_t: video output method descriptor
110  *****************************************************************************
111  * This structure is part of the video output thread descriptor.
112  * It describes the specific properties of an video output plugin
113  *****************************************************************************/
114 typedef struct vout_sys_s
115 {
116     /* Internal settings and properties */
117     int                 i_width;
118     int                 i_height;
119
120     bool                bRunning;
121     bool                bOwnsQApp;
122
123     QApplication*       pcQApplication;
124     QWidget*            pcVoutWidget;
125 } vout_sys_t;
126
127
128 /*****************************************************************************
129  * picture_sys_t: direct buffer method descriptor
130  *****************************************************************************/
131 typedef struct picture_sys_s
132 {
133     QImage*             pQImage;
134 } picture_sys_t;
135
136 extern "C"
137 {
138
139
140 /*****************************************************************************
141  *  *  * Seeking function TODO: put this in a generic location !
142  *****************************************************************************/
143 static inline void vout_Seek( off_t i_seek )
144 {
145 }
146
147
148 void _M( vout_getfunctions )( function_list_t * p_function_list );
149         
150 /*****************************************************************************
151  * Functions exported as capabilities. They are declared as static so that
152  * we don't pollute the namespace too much.
153  *****************************************************************************/
154 void _M( vout_getfunctions )( function_list_t * p_function_list )
155 {
156     p_function_list->functions.vout.pf_create     = vout_Create;
157     p_function_list->functions.vout.pf_init       = vout_Init;
158     p_function_list->functions.vout.pf_end        = vout_End;
159     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
160     p_function_list->functions.vout.pf_manage     = vout_Manage;
161     p_function_list->functions.vout.pf_render     = vout_Render;
162     p_function_list->functions.vout.pf_display    = vout_Display;
163 }
164
165 } /* extern "C" */
166
167 /*****************************************************************************
168  * vout_Create: allocate video thread output method
169  *****************************************************************************/
170 static int vout_Create( vout_thread_t *p_vout )
171 {
172     //intf_ErrMsg( "+vout_Create::qte" );
173
174     /* Allocate structure */
175     p_vout->p_sys = (vout_sys_s*) malloc( sizeof( vout_sys_t ) );
176
177     if( p_vout->p_sys == NULL )
178     {
179         intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
180         return( 1 );
181     }
182
183     memset(p_vout->p_sys, 0, sizeof( vout_sys_t ));
184
185     CreateQtWindow(p_vout);
186
187     //intf_ErrMsg( "-vout_Create::qte\n" );
188     return( 0 );
189 }
190
191 /*****************************************************************************
192  * vout_Destroy: destroy video thread output method
193  *****************************************************************************
194  * Terminate an output method created by vout_Create
195  *****************************************************************************/
196 static void vout_Destroy( vout_thread_t *p_vout )
197 {
198     //intf_ErrMsg( "+vout_Destroy::qte\n" );
199     DestroyQtWindow(p_vout);
200     free(p_vout->p_sys);
201 }
202
203 /*****************************************************************************
204  * vout_Init: initialize video thread output method
205  *****************************************************************************
206  * This function create the buffers needed by the output thread. It is called
207  * at the beginning of the thread, but also each time the window is resized.
208  *****************************************************************************/
209 static int vout_Init( vout_thread_t *p_vout )
210 {
211     int         i_index;
212         char            *psz_display, *psz_window;
213     picture_t*  p_pic;
214     int         dd = QPixmap::defaultDepth();
215
216     //intf_ErrMsg( "+vout_Init::qte\n" );
217
218    /* Initialize the output structure */
219    I_OUTPUTPICTURES = 0;
220
221    psz_display = config_GetPszVariable("qte-display");
222    psz_window = config_GetPszVariable("qte-window");
223    if( strncmp(psz_display, "portrait", 8)==0 )
224    {
225         /* All we have is an RGB image with square pixels */
226         p_vout->output.i_width  = p_vout->p_sys->i_width;
227         p_vout->output.i_height = p_vout->p_sys->i_height;
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         /* We may need to convert the chroma, but at least we keep the
235          * aspect ratio */
236         p_vout->output.i_width  = p_vout->render.i_width;
237         p_vout->output.i_height = p_vout->render.i_height;
238         p_vout->output.i_aspect = p_vout->render.i_aspect;
239     }
240
241     p_vout->output.i_chroma = (dd == 16) ? FOURCC_RV16 : FOURCC_RV32;
242     p_vout->output.i_rmask  = 0xf800;
243     p_vout->output.i_gmask  = 0x07e0;
244     p_vout->output.i_bmask  = 0x001f;
245 //    p_vout->output.i_width  = p_vout->p_sys->i_width;
246 //    p_vout->output.i_height = p_vout->p_sys->i_height;
247 //    p_vout->output.i_aspect = p_vout->render.i_aspect;
248
249     /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
250     while( I_OUTPUTPICTURES < QTE_MAX_DIRECTBUFFERS )
251     {
252         p_pic = NULL;
253
254         /* Find an empty picture slot */
255         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
256         {
257             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
258             {
259                 p_pic = p_vout->p_picture + i_index;
260                 break;
261             }
262         }
263
264         /* Allocate the picture */
265         if( p_pic == NULL ||  NewPicture( p_vout, p_pic ) )
266         {
267             break;
268         }
269
270         p_pic->i_status = DESTROYED_PICTURE;
271         p_pic->i_type   = DIRECT_PICTURE;
272
273         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
274
275         I_OUTPUTPICTURES++;
276     }
277
278     //intf_ErrMsg( "-vout_Init::qte %d output pictures\n", I_OUTPUTPICTURES);
279
280     return( 0 );
281 }
282
283
284 /*****************************************************************************
285  * vout_Render: render previously calculated output
286  *****************************************************************************/
287 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
288 {
289     //intf_ErrMsg( "+vout_Render::qte\n" );
290     ;
291 }
292
293 /*****************************************************************************
294  * vout_Display: displays previously rendered output
295  *****************************************************************************
296  * This function sends the currently rendered image to screen.
297  *****************************************************************************/
298 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
299 {
300     int x, y, w, h;
301
302     vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
303                        &x, &y, &w, &h );
304
305     if(p_vout->p_sys->pcVoutWidget)
306     {
307 // shameless borrowed from opie mediaplayer....
308 #ifndef USE_DIRECT_PAINTER
309         QPainter p(p_vout->p_sys->pcVoutWidget);
310
311         /* rotate frame */
312         int dd      = QPixmap::defaultDepth();
313         int bytes   = ( dd == 16 ) ? 2 : 4;
314         int rw = h, rh = w;
315
316         QImage rotatedFrame( rw, rh, bytes << 3 );
317
318         ushort* in  = (ushort*)p_pic->p_sys->pQImage->bits();
319         ushort* out = (ushort*)rotatedFrame.bits();
320
321         int spl = rotatedFrame.bytesPerLine() / bytes;
322         for (int x=0; x<h; x++)
323         {
324             if ( bytes == 2 )
325             {
326                 ushort* lout = out++ + (w - 1)*spl;
327                 for (int y=0; y<w; y++)
328                 {
329                     *lout=*in++;
330                     lout-=spl;
331                 }
332             }
333             else
334             {
335                 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
336                 for (int y=0; y<w; y++)
337                 {
338                     *lout=*((ulong*)in)++;
339                     lout-=spl;
340                 }
341             }
342         }
343
344         p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh );
345 #else
346         QDirectPainter p(p_vout->p_sys->pcVoutWidget);
347
348         // just copy the image to the frame buffer...
349         memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep());
350 #endif
351     }
352 }
353
354 /*****************************************************************************
355  * vout_Manage: handle QT Embedded events
356  *****************************************************************************
357  * This function should be called regularly by video output thread. It manages
358  * X11 events and allows window resizing. It returns a non null value on
359  * error.
360  *****************************************************************************/
361 static int vout_Manage( vout_thread_t *p_vout )
362 {
363     //intf_ErrMsg( "+vout_Manage::qte\n" );
364     return 0;
365 }
366
367 /*****************************************************************************
368  * vout_End: terminate video thread output method
369  *****************************************************************************
370  * Destroy the buffers created by vout_Init. It is called at the end of
371  * the thread, but also each time the window is resized.
372  *****************************************************************************/
373 static void vout_End( vout_thread_t *p_vout )
374 {
375     int i_index;
376
377     //intf_ErrMsg( "+vout_End::qte\n" );
378
379     /* Free the direct buffers we allocated */
380     for( i_index = I_OUTPUTPICTURES ; i_index ; )
381     {
382         i_index--;
383         FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
384     }
385 }
386
387
388 /*****************************************************************************
389  * NewPicture: allocate a picture
390  *****************************************************************************
391  * Returns 0 on success, -1 otherwise
392  *****************************************************************************/
393 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
394 {
395     int dd = QPixmap::defaultDepth();
396
397     //intf_ErrMsg( "+NewPicture::dd = %d\n",dd );
398
399     p_pic->p_sys = (picture_sys_t*) malloc( sizeof( picture_sys_t ) );
400
401     if( p_pic->p_sys == NULL )
402     {
403         return -1;
404     }
405
406     switch(p_vout->output.i_chroma)
407     {
408     case FOURCC_RV16:
409         if(dd == 16)
410         {
411             p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
412                                                p_vout->output.i_height,
413                                                dd );
414
415             if(p_pic->p_sys->pQImage == NULL)
416             {
417                 return -1;
418             }
419
420             p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
421
422             p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
423
424             p_pic->p->i_lines = p_vout->output.i_height;
425             p_pic->p->i_pixel_bytes = 2;
426             p_pic->p->b_margin      = 0;
427             p_pic->i_planes         = 1;
428         }
429         else
430         {
431             return -1;
432         }
433         break;
434     case FOURCC_RV32:
435         if(dd == 32)
436         {
437             p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
438                                                p_vout->output.i_height,
439                                                dd );
440
441             if(p_pic->p_sys->pQImage == NULL)
442             {
443                 return -1;
444             }
445
446             p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
447
448             p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
449
450             p_pic->p->i_lines = p_vout->output.i_height;
451             p_pic->p->i_pixel_bytes = 4;
452             p_pic->p->b_margin      = 0;
453             p_pic->i_planes         = 1;
454         }
455         else
456         {
457             return -1;
458         }
459         break;
460     default:
461         return -1;
462         break;
463     }
464
465 /*
466     intf_ErrMsg( "NewPicture: %d %d %d\n",p_vout->output.i_width,
467                                  p_vout->output.i_height,
468                                  p_vout->output.i_chroma );
469 */
470     return 0;
471 }
472
473 /*****************************************************************************
474  * FreePicture: destroy a picture allocated with NewPicture
475  *****************************************************************************/
476 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
477 {
478     delete p_pic->p_sys->pQImage;
479 }
480
481 /*****************************************************************************
482  * ToggleFullScreen: Enable or disable full screen mode
483  *****************************************************************************
484  * This function will switch between fullscreen and window mode.
485  *
486  *****************************************************************************/
487 static void ToggleFullScreen ( vout_thread_t *p_vout )
488 {
489 }
490
491
492 /*****************************************************************************
493  * CreateQtWindow: create qte applicaton / window
494  *****************************************************************************
495  * Create a window according to video output given size, and set other
496  * properties according to the display properties.
497  *****************************************************************************/
498 static int CreateQtWindow( vout_thread_t *p_vout )
499 {
500     //intf_ErrMsg( "vout_qt: +init qt window");
501
502     /* for displaying the vout in a qt window we need the QtApplication */
503     vlc_thread_t    thread_id;
504     //intf_ErrMsg( "vout_qt: +init qt window, creating qpe application");
505
506     p_vout->p_sys->pcVoutWidget = NULL;
507
508     /* create thread to exec the qpe application */
509     if ( vlc_thread_create( &thread_id, "vout qte",
510                             (vlc_thread_func_t)vout_run_qtapp_exec,
511                             (void *)p_vout) )
512     {
513         intf_ErrMsg( "input error: can't spawn vout thread");
514         return( -1 );
515     }
516
517     p_vout->p_sys->i_width  = 320;
518     p_vout->p_sys->i_height = 240;
519
520     // just wait until the crew is complete...
521     while(p_vout->p_sys->pcVoutWidget == NULL)
522     {
523         msleep(1);
524     }
525
526     //intf_ErrMsg( "vout_qt: -init qt window");
527
528     return( 0 );
529 }
530
531
532 /*****************************************************************************
533  * DestroyQtWindow: destroy the window
534  *****************************************************************************/
535 static void DestroyQtWindow( vout_thread_t *p_vout )
536 {
537     // quit qt application loop
538     if(p_vout->p_sys->pcQApplication)
539     {
540         if(p_vout->p_sys->bOwnsQApp)
541         {
542             p_vout->p_sys->pcQApplication->quit();
543         }
544         else
545         {
546             p_vout->p_sys->bRunning = FALSE;
547         }
548
549         while(p_vout->p_sys->pcVoutWidget)
550         {
551             msleep(1);
552         }
553     }
554 }
555
556 /*****************************************************************************
557  * main loop of qtapplication
558  *****************************************************************************/
559 static void*
560 vout_run_qtapp_exec(void* pVoid)
561 {
562     int     argc    = 0;
563     char    arg0[]  = "vout qte";
564
565     vout_thread_t* p_vout = (vout_thread_t*) pVoid;
566
567     if(qApp == NULL)
568     {
569         QApplication* pApp = new QApplication(argc, NULL);
570         if(pApp)
571         {
572             p_vout->p_sys->pcQApplication = pApp;
573             p_vout->p_sys->bOwnsQApp = TRUE;
574         }
575         else
576         {
577             return NULL;
578         }
579     }
580     else
581     {
582         p_vout->p_sys->pcQApplication = qApp;
583     }
584
585     {
586         QWidget vo(0, "vout");
587         vo.showFullScreen();
588         vo.show();
589         p_vout->p_sys->pcVoutWidget = &vo;
590
591         p_vout->p_sys->bRunning = TRUE;
592
593         if(p_vout->p_sys->bOwnsQApp)
594         {
595             // run the main loop of qtapplication until someone says: 'quit'
596             p_vout->p_sys->pcQApplication->exec();
597         }
598         else
599         {
600             while(p_vout->p_sys->bRunning) msleep(100);
601         }
602     }
603
604     p_vout->p_sys->pcVoutWidget = NULL;
605
606     if(p_vout->p_sys->bOwnsQApp)
607     {
608         delete p_vout->p_sys->pcQApplication;
609         p_vout->p_sys->pcQApplication = NULL;
610     }
611
612     return 0;
613 }
614