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