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