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 #include <stdlib.h>
00029 #include <string.h>
00030 #include <errno.h>
00031
00032 #include <ggi/ggi.h>
00033
00034 #include <vlc/vlc.h>
00035 #include <vlc/intf.h>
00036 #include <vlc/vout.h>
00037
00038
00039
00040
00041 static int Create ( vlc_object_t * );
00042 static void Destroy ( vlc_object_t * );
00043
00044 static int Init ( vout_thread_t * );
00045 static void End ( vout_thread_t * );
00046 static int Manage ( vout_thread_t * );
00047 static void Display ( vout_thread_t *, picture_t * );
00048
00049 static int OpenDisplay ( vout_thread_t * );
00050 static void CloseDisplay ( vout_thread_t * );
00051 static void SetPalette ( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
00052
00053
00054
00055
00056 #define DISPLAY_TEXT N_("X11 display name")
00057 #define DISPLAY_LONGTEXT N_( \
00058 "Specify the X11 hardware display you want to use.\n" \
00059 "By default, VLC will use the value of the DISPLAY " \
00060 "environment variable.")
00061
00062 vlc_module_begin();
00063 add_string( "ggi-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
00064 set_description( "General Graphics Interface video output" );
00065 set_capability( "video output", 30 );
00066 set_callbacks( Create, Destroy );
00067 vlc_module_end();
00068
00069
00070
00071
00072
00073
00074
00075 struct vout_sys_t
00076 {
00077
00078 ggi_visual_t p_display;
00079
00080 ggi_mode mode;
00081 int i_bits_per_pixel;
00082
00083
00084 ggi_directbuffer * pp_buffer[2];
00085 int i_index;
00086
00087 vlc_bool_t b_must_acquire;
00088 };
00089
00090
00091
00092
00093
00094
00095
00096
00097 static int Create( vlc_object_t *p_this )
00098 {
00099 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00100
00101
00102 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00103 if( p_vout->p_sys == NULL )
00104 {
00105 msg_Err( p_vout, "out of memory" );
00106 return( 1 );
00107 }
00108
00109
00110 if( OpenDisplay( p_vout ) )
00111 {
00112 msg_Err( p_vout, "cannot initialize GGI display" );
00113 free( p_vout->p_sys );
00114 return( 1 );
00115 }
00116
00117 p_vout->pf_init = Init;
00118 p_vout->pf_end = End;
00119 p_vout->pf_manage = Manage;
00120 p_vout->pf_render = NULL;
00121 p_vout->pf_display = Display;
00122
00123 return( 0 );
00124 }
00125
00126
00127
00128
00129
00130
00131 static int Init( vout_thread_t *p_vout )
00132 {
00133 #define p_b p_vout->p_sys->pp_buffer
00134 int i_index;
00135 picture_t *p_pic;
00136
00137 I_OUTPUTPICTURES = 0;
00138
00139 p_vout->output.i_width = p_vout->p_sys->mode.visible.x;
00140 p_vout->output.i_height = p_vout->p_sys->mode.visible.y;
00141 p_vout->output.i_aspect = p_vout->p_sys->mode.visible.x
00142 * VOUT_ASPECT_FACTOR
00143 / p_vout->p_sys->mode.visible.y;
00144
00145 switch( p_vout->p_sys->i_bits_per_pixel )
00146 {
00147 case 8:
00148 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
00149 p_vout->output.pf_setpalette = SetPalette;
00150 break;
00151 case 15:
00152 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break;
00153 case 16:
00154 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break;
00155 case 24:
00156 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break;
00157 case 32:
00158 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break;
00159 default:
00160 msg_Err( p_vout, "unknown screen depth %i",
00161 p_vout->p_sys->i_bits_per_pixel );
00162 return 0;
00163 }
00164
00165
00166 p_vout->output.i_rmask = p_b[ 0 ]->buffer.plb.pixelformat->red_mask;
00167 p_vout->output.i_gmask = p_b[ 0 ]->buffer.plb.pixelformat->green_mask;
00168 p_vout->output.i_bmask = p_b[ 0 ]->buffer.plb.pixelformat->blue_mask;
00169
00170 p_pic = NULL;
00171
00172
00173 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
00174 {
00175 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
00176 {
00177 p_pic = p_vout->p_picture + i_index;
00178 break;
00179 }
00180 }
00181
00182 if( p_pic == NULL )
00183 {
00184 return 0;
00185 }
00186
00187
00188
00189 p_vout->p_sys->i_index = 0;
00190 p_pic->p->p_pixels = p_b[ 0 ]->write;
00191 p_pic->p->i_pixel_pitch = p_b[ 0 ]->buffer.plb.pixelformat->size / 8;
00192 p_pic->p->i_lines = p_vout->p_sys->mode.visible.y;
00193 p_pic->p->i_visible_lines = p_vout->p_sys->mode.visible.y;
00194
00195 p_pic->p->i_pitch = p_b[ 0 ]->buffer.plb.stride;
00196
00197 if( p_b[ 0 ]->buffer.plb.pixelformat->size / 8
00198 * p_vout->p_sys->mode.visible.x
00199 != p_b[ 0 ]->buffer.plb.stride )
00200 {
00201 p_pic->p->i_visible_pitch = p_b[ 0 ]->buffer.plb.pixelformat->size
00202 / 8 * p_vout->p_sys->mode.visible.x;
00203 }
00204 else
00205 {
00206 p_pic->p->i_visible_pitch = p_b[ 0 ]->buffer.plb.stride;
00207 }
00208
00209 p_pic->i_planes = 1;
00210
00211 p_pic->i_status = DESTROYED_PICTURE;
00212 p_pic->i_type = DIRECT_PICTURE;
00213
00214 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
00215
00216 I_OUTPUTPICTURES++;
00217
00218
00219 if( p_vout->p_sys->b_must_acquire )
00220 {
00221 ggiResourceAcquire( p_b[ 0 ]->resource,
00222 GGI_ACTYPE_WRITE );
00223 }
00224
00225
00226 ggiSetEventMask( p_vout->p_sys->p_display,
00227 emKeyboard | emPtrButtonPress | emPtrButtonRelease );
00228
00229
00230 ggiAddFlags( p_vout->p_sys->p_display, GGIFLAG_ASYNC );
00231
00232 return( 0 );
00233 #undef p_b
00234 }
00235
00236
00237
00238
00239
00240
00241 static void End( vout_thread_t *p_vout )
00242 {
00243 #define p_b p_vout->p_sys->pp_buffer
00244
00245 if( p_vout->p_sys->b_must_acquire )
00246 {
00247 ggiResourceRelease( p_b[ p_vout->p_sys->i_index ]->resource );
00248 }
00249 #undef p_b
00250 }
00251
00252
00253
00254
00255
00256
00257 static void Destroy( vlc_object_t *p_this )
00258 {
00259 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00260
00261 CloseDisplay( p_vout );
00262
00263 free( p_vout->p_sys );
00264 }
00265
00266
00267
00268
00269
00270
00271
00272 static int Manage( vout_thread_t *p_vout )
00273 {
00274 struct timeval tv = { 0, 1000 };
00275 gii_event_mask mask;
00276 gii_event event;
00277 vlc_value_t val;
00278
00279 mask = emKeyboard | emPtrButtonPress | emPtrButtonRelease;
00280
00281 ggiEventPoll( p_vout->p_sys->p_display, mask, &tv );
00282
00283 while( ggiEventsQueued( p_vout->p_sys->p_display, mask) )
00284 {
00285 ggiEventRead( p_vout->p_sys->p_display, &event, mask);
00286
00287 switch( event.any.type )
00288 {
00289 case evKeyRelease:
00290
00291 switch( event.key.sym )
00292 {
00293 case 'q':
00294 case 'Q':
00295 case GIIUC_Escape:
00296 p_vout->p_vlc->b_die = 1;
00297 break;
00298
00299 default:
00300 break;
00301 }
00302 break;
00303
00304 case evPtrButtonRelease:
00305
00306 switch( event.pbutton.button )
00307 {
00308 case GII_PBUTTON_LEFT:
00309 val.b_bool = VLC_TRUE;
00310 var_Set( p_vout, "mouse-clicked", val );
00311 break;
00312
00313 case GII_PBUTTON_RIGHT:
00314 {
00315 intf_thread_t *p_intf;
00316 p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF,
00317 FIND_ANYWHERE );
00318 if( p_intf )
00319 {
00320 p_intf->b_menu_change = 1;
00321 vlc_object_release( p_intf );
00322 }
00323 }
00324 break;
00325 }
00326 break;
00327
00328 default:
00329 break;
00330 }
00331 }
00332
00333 return( 0 );
00334 }
00335
00336
00337
00338
00339 static void Display( vout_thread_t *p_vout, picture_t *p_pic )
00340 {
00341 #define p_b p_vout->p_sys->pp_buffer
00342 p_pic->p->p_pixels = p_b[ p_vout->p_sys->i_index ]->write;
00343
00344
00345 if( p_vout->p_sys->b_must_acquire )
00346 {
00347 ggiResourceRelease( p_b[ p_vout->p_sys->i_index ]->resource );
00348 }
00349 ggiSetDisplayFrame( p_vout->p_sys->p_display,
00350 p_b[ p_vout->p_sys->i_index ]->frame );
00351
00352
00353 p_vout->p_sys->i_index ^= 1;
00354 p_pic->p->p_pixels = p_b[ p_vout->p_sys->i_index ]->write;
00355
00356 if( p_vout->p_sys->b_must_acquire )
00357 {
00358 ggiResourceAcquire( p_b[ p_vout->p_sys->i_index ]->resource,
00359 GGI_ACTYPE_WRITE );
00360 }
00361 ggiSetWriteFrame( p_vout->p_sys->p_display,
00362 p_b[ p_vout->p_sys->i_index ]->frame );
00363
00364
00365 ggiFlush( p_vout->p_sys->p_display );
00366 #undef p_b
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 static int OpenDisplay( vout_thread_t *p_vout )
00378 {
00379 #define p_b p_vout->p_sys->pp_buffer
00380 ggi_color col_fg;
00381 ggi_color col_bg;
00382 int i_index;
00383 char *psz_display;
00384
00385
00386 if( ggiInit() )
00387 {
00388 msg_Err( p_vout, "cannot initialize GGI library" );
00389 return( 1 );
00390 }
00391
00392
00393 psz_display = config_GetPsz( p_vout, "ggi_display" );
00394
00395 p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
00396 if( psz_display ) free( psz_display );
00397
00398 if( p_vout->p_sys->p_display == NULL )
00399 {
00400 msg_Err( p_vout, "cannot open GGI default display" );
00401 ggiExit();
00402 return( 1 );
00403 }
00404
00405
00406 p_vout->p_sys->mode.frames = 2;
00407 p_vout->p_sys->mode.visible.x = config_GetInt( p_vout, "width" );
00408 p_vout->p_sys->mode.visible.y = config_GetInt( p_vout, "height" );
00409 p_vout->p_sys->mode.virt.x = GGI_AUTO;
00410 p_vout->p_sys->mode.virt.y = GGI_AUTO;
00411 p_vout->p_sys->mode.size.x = GGI_AUTO;
00412 p_vout->p_sys->mode.size.y = GGI_AUTO;
00413 p_vout->p_sys->mode.graphtype = GT_15BIT;
00414 p_vout->p_sys->mode.dpp.x = GGI_AUTO;
00415 p_vout->p_sys->mode.dpp.y = GGI_AUTO;
00416 ggiCheckMode( p_vout->p_sys->p_display, &p_vout->p_sys->mode );
00417
00418
00419
00420
00421 if( ggiSetMode( p_vout->p_sys->p_display, &p_vout->p_sys->mode ) )
00422 {
00423 msg_Err( p_vout, "cannot set GGI mode" );
00424 ggiClose( p_vout->p_sys->p_display );
00425 ggiExit();
00426 return( 1 );
00427 }
00428
00429
00430 p_vout->p_sys->b_must_acquire = 0;
00431 for( i_index = 0; i_index < 2; i_index++ )
00432 {
00433
00434 p_vout->p_sys->pp_buffer[ i_index ] =
00435 (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display,
00436 i_index );
00437 if( p_b[ i_index ] == NULL )
00438 {
00439 msg_Err( p_vout, "double buffering is not possible" );
00440 ggiClose( p_vout->p_sys->p_display );
00441 ggiExit();
00442 return( 1 );
00443 }
00444
00445
00446 if( ! ( p_b[ i_index ]->type & GGI_DB_SIMPLE_PLB )
00447 || ( p_b[ i_index ]->page_size != 0 )
00448 || ( p_b[ i_index ]->write == NULL )
00449 || ( p_b[ i_index ]->noaccess != 0 )
00450 || ( p_b[ i_index ]->align != 0 ) )
00451 {
00452 msg_Err( p_vout, "incorrect video memory type" );
00453 ggiClose( p_vout->p_sys->p_display );
00454 ggiExit();
00455 return( 1 );
00456 }
00457
00458
00459 if( ggiResourceMustAcquire( p_b[ i_index ]->resource ) )
00460 {
00461 p_vout->p_sys->b_must_acquire = 1;
00462 }
00463 }
00464
00465
00466 col_fg.r = col_fg.g = col_fg.b = -1;
00467 col_bg.r = col_bg.g = col_bg.b = 0;
00468 if( ggiSetGCForeground(p_vout->p_sys->p_display,
00469 ggiMapColor(p_vout->p_sys->p_display,&col_fg)) ||
00470 ggiSetGCBackground(p_vout->p_sys->p_display,
00471 ggiMapColor(p_vout->p_sys->p_display,&col_bg)) )
00472 {
00473 msg_Err( p_vout, "cannot set colors" );
00474 ggiClose( p_vout->p_sys->p_display );
00475 ggiExit();
00476 return( 1 );
00477 }
00478
00479
00480 if( ggiSetGCClipping( p_vout->p_sys->p_display, 0, 0,
00481 p_vout->p_sys->mode.visible.x,
00482 p_vout->p_sys->mode.visible.y ) )
00483 {
00484 msg_Err( p_vout, "cannot set clipping" );
00485 ggiClose( p_vout->p_sys->p_display );
00486 ggiExit();
00487 return( 1 );
00488 }
00489
00490
00491 p_vout->p_sys->i_bits_per_pixel = p_b[ 0 ]->buffer.plb.pixelformat->depth;
00492
00493 return( 0 );
00494 #undef p_b
00495 }
00496
00497
00498
00499
00500
00501
00502
00503 static void CloseDisplay( vout_thread_t *p_vout )
00504 {
00505
00506 ggiClose( p_vout->p_sys->p_display );
00507
00508
00509 ggiExit();
00510 }
00511
00512
00513
00514
00515 static void SetPalette( vout_thread_t *p_vout,
00516 uint16_t *red, uint16_t *green, uint16_t *blue )
00517 {
00518 ggi_color colors[256];
00519 int i;
00520
00521
00522 for( i = 0; i < 256; i++ )
00523 {
00524 colors[ i ].r = red[ i ];
00525 colors[ i ].g = green[ i ];
00526 colors[ i ].b = blue[ i ];
00527 colors[ i ].a = 0;
00528 }
00529
00530
00531 if( ggiSetPalette( p_vout->p_sys->p_display, 0, 256, colors ) < 0 )
00532 {
00533 msg_Err( p_vout, "failed setting palette" );
00534 }
00535 }
00536