00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 extern "C"
00038 {
00039 #include <errno.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042
00043 #include <vlc/vlc.h>
00044 #include <vlc/intf.h>
00045 #include <vlc/vout.h>
00046
00047 #ifdef HAVE_MACHINE_PARAM_H
00048
00049 # include <machine/param.h>
00050 # include <sys/types.h>
00051 # include <sys/ipc.h>
00052 #endif
00053
00054 #ifndef WIN32
00055 # include <netinet/in.h>
00056 #endif
00057
00058 #ifdef HAVE_SYS_SHM_H
00059 # include <sys/shm.h>
00060 #endif
00061 }
00062
00063 #include <qapplication.h>
00064 #include <qpainter.h>
00065
00066 #ifdef Q_WS_QWS
00067 # define USE_DIRECT_PAINTER
00068 # include <qdirectpainter_qws.h>
00069 # include <qgfxraster_qws.h>
00070 #endif
00071
00072 extern "C"
00073 {
00074 #include "qte.h"
00075
00076
00077
00078
00079 #define DISPLAY_TEXT N_("QT Embedded display name")
00080 #define DISPLAY_LONGTEXT N_( \
00081 "Specify the Qt Embedded hardware display you want to use. " \
00082 "By default VLC will use the value of the DISPLAY environment variable.")
00083
00084
00085
00086
00087 static int Open ( vlc_object_t * );
00088 static void Close ( vlc_object_t * );
00089 static void Render ( vout_thread_t *, picture_t * );
00090 static void Display ( vout_thread_t *, picture_t * );
00091 static int Manage ( vout_thread_t * );
00092 static int Init ( vout_thread_t * );
00093 static void End ( vout_thread_t * );
00094
00095 static int OpenDisplay ( vout_thread_t * );
00096 static void CloseDisplay( vout_thread_t * );
00097
00098 static int NewPicture ( vout_thread_t *, picture_t * );
00099 static void FreePicture ( vout_thread_t *, picture_t * );
00100
00101 static void ToggleFullScreen ( vout_thread_t * );
00102
00103 static void RunQtThread( event_thread_t *p_event );
00104 }
00105
00106
00107
00108
00109 extern "C"
00110 {
00111
00112 vlc_module_begin();
00113 set_category( CAT_VIDEO );
00114 set_subcategory( SUBCAT_VIDEO_VOUT );
00115
00116
00117 set_description( _("QT Embedded video output") );
00118 set_capability( "video output", 70 );
00119 add_shortcut( "qte" );
00120 set_callbacks( Open, Close);
00121 vlc_module_end();
00122
00123 }
00124
00125
00126
00127
00128 static inline void vout_Seek( off_t i_seek )
00129 {
00130 }
00131
00132
00133
00134
00135 static int Open( vlc_object_t *p_this )
00136 {
00137 vout_thread_t * p_vout = (vout_thread_t *)p_this;
00138
00139
00140 p_vout->p_sys = (struct vout_sys_t*) malloc( sizeof( struct vout_sys_t ) );
00141
00142 if( p_vout->p_sys == NULL )
00143 {
00144 msg_Err( p_vout, "out of memory" );
00145 return( 1 );
00146 }
00147
00148 p_vout->pf_init = Init;
00149 p_vout->pf_end = End;
00150 p_vout->pf_manage = Manage;
00151 p_vout->pf_render = NULL;
00152 p_vout->pf_display = Display;
00153
00154 #ifdef NEED_QTE_MAIN
00155 p_vout->p_sys->p_qte_main =
00156 module_Need( p_this, "gui-helper", "qte", VLC_TRUE );
00157 if( p_vout->p_sys->p_qte_main == NULL )
00158 {
00159 free( p_vout->p_sys );
00160 return VLC_ENOMOD;
00161 }
00162 #endif
00163
00164 if (OpenDisplay(p_vout))
00165 {
00166 msg_Err( p_vout, "Cannot set up qte video output" );
00167 Close(p_this);
00168 return( -1 );
00169 }
00170 return( 0 );
00171 }
00172
00173
00174
00175
00176
00177
00178 static void Close ( vlc_object_t *p_this )
00179 {
00180 vout_thread_t * p_vout = (vout_thread_t *)p_this;
00181
00182 msg_Dbg( p_vout, "close" );
00183 if( p_vout->p_sys->p_event )
00184 {
00185 vlc_object_detach( p_vout->p_sys->p_event );
00186
00187
00188 p_vout->p_sys->p_event->b_die = VLC_TRUE;
00189 CloseDisplay(p_vout);
00190
00191 vlc_thread_join( p_vout->p_sys->p_event );
00192 vlc_object_destroy( p_vout->p_sys->p_event );
00193 }
00194
00195 #ifdef NEED_QTE_MAIN
00196 msg_Dbg( p_vout, "releasing gui-helper" );
00197 module_Unneed( p_vout, p_vout->p_sys->p_qte_main );
00198 #endif
00199
00200 if( p_vout->p_sys )
00201 {
00202 free( p_vout->p_sys );
00203 p_vout->p_sys = NULL;
00204 }
00205 }
00206
00207
00208
00209
00210
00211
00212
00213 static int Init( vout_thread_t *p_vout )
00214 {
00215 int i_index;
00216 picture_t* p_pic;
00217 int dd = QPixmap::defaultDepth();
00218
00219 I_OUTPUTPICTURES = 0;
00220
00221 p_vout->output.i_chroma = (dd == 16) ? VLC_FOURCC('R','V','1','6'): VLC_FOURCC('R','V','3','2');
00222 p_vout->output.i_rmask = 0xf800;
00223 p_vout->output.i_gmask = 0x07e0;
00224 p_vout->output.i_bmask = 0x001f;
00225
00226
00227 p_vout->output.i_width = p_vout->p_sys->i_width;
00228 p_vout->output.i_height = p_vout->p_sys->i_height;
00229 if( !p_vout->b_fullscreen )
00230 {
00231 p_vout->output.i_aspect = p_vout->output.i_width
00232 * VOUT_ASPECT_FACTOR
00233 / p_vout->output.i_height;
00234 }
00235 else
00236 {
00237 p_vout->output.i_aspect = p_vout->render.i_aspect;
00238 }
00239 #if 0
00240 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 );
00241 #endif
00242
00243 while( I_OUTPUTPICTURES < QTE_MAX_DIRECTBUFFERS )
00244 {
00245 p_pic = NULL;
00246
00247
00248 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
00249 {
00250 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
00251 {
00252 p_pic = p_vout->p_picture + i_index;
00253 break;
00254 }
00255 }
00256
00257
00258 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
00259 {
00260 break;
00261 }
00262
00263 p_pic->i_status = DESTROYED_PICTURE;
00264 p_pic->i_type = DIRECT_PICTURE;
00265
00266 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
00267
00268 I_OUTPUTPICTURES++;
00269 }
00270
00271 return( 0 );
00272 }
00273
00274
00275
00276
00277
00278 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
00279 {
00280 ;
00281 }
00282
00283
00284
00285
00286
00287
00288 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
00289 {
00290 unsigned int x, y, w, h;
00291
00292 vout_PlacePicture( p_vout, p_vout->output.i_width, p_vout->output.i_height,
00293 &x, &y, &w, &h );
00294 #if 0
00295 msg_Dbg(p_vout, "+qte::Display( p_vout, i_width=%d, i_height=%d, x=%u, y=%u, w=%u, h=%u",
00296 p_vout->output.i_width, p_vout->output.i_height, x, y, w, h );
00297 #endif
00298
00299 if(p_vout->p_sys->p_VideoWidget)
00300 {
00301
00302 #ifndef USE_DIRECT_PAINTER
00303 msg_Dbg(p_vout, "not using direct painter");
00304 QPainter p(p_vout->p_sys->p_VideoWidget);
00305
00306
00307 int dd = QPixmap::defaultDepth();
00308 int bytes = ( dd == 16 ) ? 2 : 4;
00309 int rw = h, rh = w;
00310
00311 QImage rotatedFrame( rw, rh, bytes << 3 );
00312
00313 ushort* in = (ushort*)p_pic->p_sys->pQImage->bits();
00314 ushort* out = (ushort*)rotatedFrame.bits();
00315
00316 int spl = rotatedFrame.bytesPerLine() / bytes;
00317 for (int x=0; x<h; x++)
00318 {
00319 if ( bytes == 2 )
00320 {
00321 ushort* lout = out++ + (w - 1)*spl;
00322 for (int y=0; y<w; y++)
00323 {
00324 *lout=*in++;
00325 lout-=spl;
00326 }
00327 }
00328 else
00329 {
00330 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
00331 for (int y=0; y<w; y++)
00332 {
00333 *lout=*((ulong*)in)++;
00334 lout-=spl;
00335 }
00336 }
00337 }
00338
00339 p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh );
00340 #else
00341 QDirectPainter p(p_vout->p_sys->p_VideoWidget);
00342 p.transformOrientation();
00343
00344 memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep());
00345 #endif
00346 }
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356 static int Manage( vout_thread_t *p_vout )
00357 {
00358
00359
00360
00361 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
00362 {
00363 p_vout->b_fullscreen = ! p_vout->b_fullscreen;
00364
00365
00366
00367
00368
00369 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
00370 p_vout->i_changes |= VOUT_SIZE_CHANGE;
00371 }
00372
00373
00374
00375
00376 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
00377 {
00378 msg_Dbg( p_vout, "video display resized (%dx%d)",
00379 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
00380
00381 CloseDisplay( p_vout );
00382 OpenDisplay( p_vout );
00383
00384
00385
00386 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
00387 }
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 return 0;
00402 }
00403
00404
00405
00406
00407
00408
00409
00410 static void End( vout_thread_t *p_vout )
00411 {
00412 int i_index;
00413
00414
00415 for( i_index = I_OUTPUTPICTURES ; i_index ; )
00416 {
00417 i_index--;
00418 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
00419 }
00420 }
00421
00422
00423
00424
00425
00426
00427
00428 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
00429 {
00430 int dd = QPixmap::defaultDepth();
00431
00432 p_pic->p_sys = (picture_sys_t*) malloc( sizeof( picture_sys_t ) );
00433 if( p_pic->p_sys == NULL )
00434 {
00435 return -1;
00436 }
00437
00438
00439 p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
00440 p_vout->output.i_height, dd );
00441
00442 if(p_pic->p_sys->pQImage == NULL)
00443 {
00444 return -1;
00445 }
00446
00447 switch( dd )
00448 {
00449 case 8:
00450 p_pic->p->i_pixel_pitch = 1;
00451 break;
00452 case 15:
00453 case 16:
00454 p_pic->p->i_pixel_pitch = 2;
00455 break;
00456 case 24:
00457 case 32:
00458 p_pic->p->i_pixel_pitch = 4;
00459 break;
00460 default:
00461 return( -1 );
00462 }
00463
00464 p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
00465 p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
00466 p_pic->p->i_lines = p_vout->output.i_height;
00467 p_pic->p->i_visible_lines = p_vout->output.i_height;
00468 p_pic->p->i_visible_pitch =
00469 p_pic->p->i_pixel_pitch * p_vout->output.i_width;
00470
00471 p_pic->i_planes = 1;
00472
00473 return 0;
00474 }
00475
00476
00477
00478
00479 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
00480 {
00481 delete p_pic->p_sys->pQImage;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490 static void ToggleFullScreen ( vout_thread_t *p_vout )
00491 {
00492 if ( p_vout->b_fullscreen )
00493 p_vout->p_sys->p_VideoWidget->showFullScreen();
00494 else
00495 p_vout->p_sys->p_VideoWidget->showNormal();
00496
00497 p_vout->b_fullscreen = !p_vout->b_fullscreen;
00498 }
00499
00500
00501
00502
00503
00504
00505
00506 static int OpenDisplay( vout_thread_t *p_vout )
00507 {
00508
00509 p_vout->p_sys->p_QApplication = NULL;
00510 p_vout->p_sys->p_VideoWidget = NULL;
00511
00512 p_vout->p_sys->p_event = (event_thread_t*) vlc_object_create( p_vout, sizeof(event_thread_t) );
00513 p_vout->p_sys->p_event->p_vout = p_vout;
00514
00515
00516 #if 1
00517 p_vout->b_fullscreen = VLC_TRUE;
00518 #endif
00519
00520
00521 QWidget *desktop = p_vout->p_sys->p_QApplication->desktop();
00522 p_vout->p_sys->i_width = p_vout->b_fullscreen ? desktop->height() :
00523 p_vout->i_window_width;
00524 p_vout->p_sys->i_height = p_vout->b_fullscreen ? desktop->width() :
00525 p_vout->i_window_height;
00526
00527 #if 0
00528
00529 p_vout->i_changes |= VOUT_SIZE_CHANGE;
00530 p_vout->i_window_width = p_vout->p_sys->i_width;
00531 p_vout->i_window_height = p_vout->p_sys->i_height;
00532 #endif
00533
00534 msg_Dbg( p_vout, "OpenDisplay (h=%d,w=%d)",p_vout->p_sys->i_height,p_vout->p_sys->i_width);
00535
00536
00537 if ( vlc_thread_create( p_vout->p_sys->p_event, "QT Embedded Thread",
00538 RunQtThread,
00539 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE) )
00540 {
00541 msg_Err( p_vout, "cannot create QT Embedded Thread" );
00542 vlc_object_destroy( p_vout->p_sys->p_event );
00543 p_vout->p_sys->p_event = NULL;
00544 return -1;
00545 }
00546
00547 if( p_vout->p_sys->p_event->b_error )
00548 {
00549 msg_Err( p_vout, "RunQtThread failed" );
00550 return -1;
00551 }
00552
00553 vlc_object_attach( p_vout->p_sys->p_event, p_vout );
00554 msg_Dbg( p_vout, "RunQtThread running" );
00555
00556
00557 while(p_vout->p_sys->p_VideoWidget == NULL)
00558 {
00559 msleep(1);
00560 }
00561 return VLC_SUCCESS;
00562 }
00563
00564
00565
00566
00567
00568 static void CloseDisplay( vout_thread_t *p_vout )
00569 {
00570
00571 msg_Dbg( p_vout, "destroying Qt Window" );
00572 #ifdef NEED_QTE_MAIN
00573 if(p_vout->p_sys->p_QApplication)
00574 {
00575 p_vout->p_sys->bRunning = FALSE;
00576 while(p_vout->p_sys->p_VideoWidget)
00577 {
00578 msleep(1);
00579 }
00580 }
00581 #else
00582 if (p_vout->p_sys->p_QApplication)
00583 p_vout->p_sys->p_QApplication->quit();
00584 #endif
00585 }
00586
00587
00588
00589
00590 static void RunQtThread(event_thread_t *p_event)
00591 {
00592 msg_Dbg( p_event->p_vout, "RunQtThread Starting" );
00593
00594 #ifdef NEED_QTE_MAIN
00595 if (qApp)
00596 {
00597 p_event->p_vout->p_sys->p_QApplication = qApp;
00598 p_event->p_vout->p_sys->bOwnsQApp = FALSE;
00599 p_event->p_vout->p_sys->p_VideoWidget = qApp->mainWidget();
00600 msg_Dbg( p_event->p_vout, "RunQtThread applicaton attached" );
00601 }
00602 #else
00603 if (qApp==NULL)
00604 {
00605 int argc = 0;
00606 QApplication* pApp = new QApplication(argc, NULL);
00607 if(pApp)
00608 {
00609 p_event->p_vout->p_sys->p_QApplication = pApp;
00610 p_event->p_vout->p_sys->bOwnsQApp = TRUE;
00611 }
00612 QWidget* pWidget = new QWidget();
00613 if (pWidget)
00614 {
00615 p_event->p_vout->p_sys->p_VideoWidget = pWidget;
00616 }
00617 }
00618 #endif
00619
00620 vlc_thread_ready( p_event );
00621 msg_Dbg( p_event->p_vout, "RunQtThread ready" );
00622
00623 if (p_event->p_vout->p_sys->p_QApplication)
00624 {
00625
00626 QWidget *desktop = p_event->p_vout->p_sys->p_QApplication->desktop();
00627 p_event->p_vout->p_sys->p_VideoWidget->setMinimumWidth( 10 );
00628 p_event->p_vout->p_sys->p_VideoWidget->setMinimumHeight( 10 );
00629 p_event->p_vout->p_sys->p_VideoWidget->setBaseSize( p_event->p_vout->p_sys->i_width,
00630 p_event->p_vout->p_sys->i_height );
00631 p_event->p_vout->p_sys->p_VideoWidget->setMaximumWidth( desktop->width() );
00632 p_event->p_vout->p_sys->p_VideoWidget->setMaximumHeight( desktop->height() );
00633
00634 if (p_event->p_vout->b_fullscreen)
00635 p_event->p_vout->p_sys->p_VideoWidget->showFullScreen();
00636 else
00637 p_event->p_vout->p_sys->p_VideoWidget->showNormal();
00638
00639 p_event->p_vout->p_sys->p_VideoWidget->show();
00640 p_event->p_vout->p_sys->bRunning = TRUE;
00641
00642 #ifdef NEED_QTE_MAIN
00643 while(!p_event->b_die && p_event->p_vout->p_sys->bRunning)
00644 {
00645
00646 if( p_event->b_die )
00647 break;
00648
00649 msleep(100);
00650 }
00651 #else
00652
00653 p_event->p_vout->p_sys->pcQApplication->exec();
00654 #endif
00655 }
00656
00657 #ifndef NEED_QTE_MAIN
00658 if(p_event->p_vout->p_sys->p_QApplication)
00659 {
00660 delete p_event->p_vout->p_sys->p_VideoWidget;
00661 p_event->p_vout->p_sys->p_VideoWidget = NULL;
00662 delete p_event->p_vout->p_sys->p_QApplication;
00663 p_event->p_vout->p_sys->p_QApplication = NULL;
00664 }
00665 #else
00666 p_event->p_vout->p_sys->p_VideoWidget = NULL;
00667 #endif
00668
00669 msg_Dbg( p_event->p_vout, "RunQtThread terminating" );
00670 }
00671