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 #include <stdlib.h>
00028 #include <string.h>
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc_config.h>
00032 #include <vlc_video.h>
00033
00034 #include <vlc_keys.h>
00035 #include <vlc_image.h>
00036 #include <vlc_osd.h>
00037
00038
00039 #undef OSD_MENU_DEBUG
00040
00041
00042
00043
00044 static const char *ppsz_button_states[] = { "unselect", "select", "pressed" };
00045
00046
00047 static osd_menu_t *osd_MenuNew( osd_menu_t *, const char *, int, int );
00048 static osd_button_t *osd_ButtonNew( const char *, int, int );
00049 static osd_state_t *osd_StateNew( vlc_object_t *, const char *, const char * );
00050
00051 static void osd_MenuFree ( vlc_object_t *, osd_menu_t * );
00052 static void osd_ButtonFree( vlc_object_t *, osd_button_t * );
00053 static void osd_StatesFree( vlc_object_t *, osd_state_t * );
00054
00055 static picture_t *osd_LoadImage( vlc_object_t *, const char *);
00056
00057
00058
00059
00060 static picture_t *osd_LoadImage( vlc_object_t *p_this, const char *psz_filename )
00061 {
00062 picture_t *p_pic = NULL;
00063 image_handler_t *p_image;
00064 video_format_t fmt_in = {0}, fmt_out = {0};
00065
00066 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
00067 p_image = image_HandlerCreate( p_this );
00068 if( p_image )
00069 {
00070 p_pic = image_ReadUrl( p_image, psz_filename, &fmt_in, &fmt_out );
00071 image_HandlerDelete( p_image );
00072 #if 0
00073 p_pic = osd_YuvaYuvp( p_this, p_pic );
00074 #endif
00075 }
00076 else msg_Err( p_this, "unable to handle this chroma" );
00077
00078 return p_pic;
00079 }
00080
00081
00082
00083
00084 static osd_menu_t *osd_MenuNew( osd_menu_t *p_menu, const char *psz_path, int i_x, int i_y )
00085 {
00086 if( !p_menu ) return NULL;
00087
00088 p_menu->p_state = (osd_menu_state_t *) malloc( sizeof( osd_menu_state_t ) );
00089 if( !p_menu->p_state )
00090 msg_Err( p_menu, "memory allocation for OSD Menu state failed." );
00091
00092 if( psz_path != NULL )
00093 p_menu->psz_path = strdup( psz_path );
00094 else
00095 p_menu->psz_path = NULL;
00096 p_menu->i_x = i_x;
00097 p_menu->i_y = i_y;
00098
00099 return p_menu;
00100 }
00101
00102
00103
00104
00105 static void osd_MenuFree( vlc_object_t *p_this, osd_menu_t *p_menu )
00106 {
00107 msg_Dbg( p_this, "freeing menu" );
00108 osd_ButtonFree( p_this, p_menu->p_button );
00109 p_menu->p_button = NULL;
00110 p_menu->p_last_button = NULL;
00111 if( p_menu->psz_path ) free( p_menu->psz_path );
00112 p_menu->psz_path = NULL;
00113 if( p_menu->p_state ) free( p_menu->p_state );
00114 p_menu->p_state = NULL;
00115 }
00116
00117
00118
00119
00120 static osd_button_t *osd_ButtonNew( const char *psz_action, int i_x, int i_y )
00121 {
00122 osd_button_t *p_button = NULL;
00123 p_button = (osd_button_t*) malloc( sizeof(osd_button_t) );
00124 if( !p_button )
00125 return NULL;
00126
00127 memset( p_button, 0, sizeof(osd_button_t) );
00128 p_button->psz_action = strdup(psz_action);
00129 p_button->psz_action_down = NULL;
00130 p_button->p_feedback = NULL;
00131 p_button->i_x = i_x;
00132 p_button->i_y = i_y;
00133
00134 return p_button;
00135 }
00136
00137
00138
00139
00140 static void osd_ButtonFree( vlc_object_t *p_this, osd_button_t *p_button )
00141 {
00142 osd_button_t *p_current = p_button;
00143 osd_button_t *p_next = NULL;
00144 osd_button_t *p_prev = NULL;
00145
00146
00147 while( p_current->p_next )
00148 {
00149 p_next = p_current->p_next;
00150 p_current = p_next;
00151 }
00152
00153 while( p_current->p_prev )
00154 {
00155 msg_Dbg( p_this, "+ freeing button %s [%p]", p_current->psz_action, p_current );
00156 p_prev = p_current->p_prev;
00157 p_current = p_prev;
00158 if( p_current->p_next )
00159 {
00160 if( p_current->p_next->psz_name )
00161 free( p_current->p_next->psz_name );
00162 if( p_current->p_next->psz_action )
00163 free( p_current->p_next->psz_action );
00164 if( p_current->p_next->psz_action_down )
00165 free( p_current->p_next->psz_action_down );
00166 if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
00167 free( p_current->p_feedback->p_data_orig );
00168 if( p_current->p_feedback )
00169 free( p_current->p_feedback );
00170
00171 p_current->p_next->psz_action_down = NULL;
00172 p_current->p_next->psz_action = NULL;
00173 p_current->p_next->psz_name = NULL;
00174 p_current->p_feedback = NULL;
00175
00176
00177 if( p_current->p_next->p_states )
00178 osd_StatesFree( p_this, p_current->p_next->p_states );
00179 p_current->p_next->p_states = NULL;
00180 if( p_current->p_next) free( p_current->p_next );
00181 p_current->p_next = NULL;
00182 }
00183
00184 if( p_current->p_up )
00185 {
00186 if( p_current->p_up->psz_name )
00187 free( p_current->p_up->psz_name );
00188 if( p_current->p_up->psz_action )
00189 free( p_current->p_up->psz_action );
00190 if( p_current->p_up->psz_action_down )
00191 free( p_current->p_up->psz_action_down );
00192 if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
00193 free( p_current->p_feedback->p_data_orig );
00194 if( p_current->p_feedback )
00195 free( p_current->p_feedback );
00196
00197 p_current->p_up->psz_action_down = NULL;
00198 p_current->p_up->psz_action = NULL;
00199 p_current->p_up->psz_name = NULL;
00200 p_current->p_feedback = NULL;
00201
00202
00203 if( p_current->p_up->p_states )
00204 osd_StatesFree( p_this, p_current->p_up->p_states );
00205 p_current->p_up->p_states = NULL;
00206 if( p_current->p_up ) free( p_current->p_up );
00207 p_current->p_up = NULL;
00208 }
00209 }
00210
00211 if( p_button )
00212 {
00213 msg_Dbg( p_this, "+ freeing button %s [%p]", p_button->psz_action, p_button );
00214 if( p_button->psz_name ) free( p_button->psz_name );
00215 if( p_button->psz_action ) free( p_button->psz_action );
00216 if( p_button->psz_action_down ) free( p_button->psz_action_down );
00217 if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
00218 free( p_current->p_feedback->p_data_orig );
00219 if( p_current->p_feedback )
00220 free( p_current->p_feedback );
00221
00222 p_button->psz_name = NULL;
00223 p_button->psz_action = NULL;
00224 p_button->psz_action_down = NULL;
00225 p_current->p_feedback = NULL;
00226
00227 if( p_button->p_states )
00228 osd_StatesFree( p_this, p_button->p_states );
00229 p_button->p_states = NULL;
00230 free( p_button );
00231 p_button = NULL;
00232 }
00233 }
00234
00235
00236
00237
00238 static osd_state_t *osd_StateNew( vlc_object_t *p_this, const char *psz_file, const char *psz_state )
00239 {
00240 osd_state_t *p_state = NULL;
00241 p_state = (osd_state_t*) malloc( sizeof(osd_state_t) );
00242 if( !p_state )
00243 return NULL;
00244
00245 memset( p_state, 0, sizeof(osd_state_t) );
00246 p_state->p_pic = osd_LoadImage( p_this, psz_file );
00247
00248 if( psz_state )
00249 {
00250 p_state->psz_state = strdup( psz_state );
00251 if( strncmp( ppsz_button_states[0], psz_state, strlen(ppsz_button_states[0]) ) == 0 )
00252 p_state->i_state = OSD_BUTTON_UNSELECT;
00253 else if( strncmp( ppsz_button_states[1], psz_state, strlen(ppsz_button_states[1]) ) == 0 )
00254 p_state->i_state = OSD_BUTTON_SELECT;
00255 else if( strncmp( ppsz_button_states[2], psz_state, strlen(ppsz_button_states[2]) ) == 0 )
00256 p_state->i_state = OSD_BUTTON_PRESSED;
00257 }
00258 return p_state;
00259 }
00260
00261
00262
00263
00264 static void osd_StatesFree( vlc_object_t *p_this, osd_state_t *p_states )
00265 {
00266 osd_state_t *p_state = p_states;
00267 osd_state_t *p_next = NULL;
00268 osd_state_t *p_prev = NULL;
00269
00270 while( p_state->p_next )
00271 {
00272 p_next = p_state->p_next;
00273 p_state = p_next;
00274 }
00275
00276 while( p_state->p_prev )
00277 {
00278 msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_state );
00279 p_prev = p_state->p_prev;
00280 p_state = p_prev;
00281 if( p_state->p_next )
00282 {
00283 if( p_state->p_next->p_pic && p_state->p_next->p_pic->p_data_orig )
00284 free( p_state->p_next->p_pic->p_data_orig );
00285 if( p_state->p_next->p_pic ) free( p_state->p_next->p_pic );
00286 p_state->p_next->p_pic = NULL;
00287 if( p_state->p_next->psz_state ) free( p_state->p_next->psz_state );
00288 p_state->p_next->psz_state = NULL;
00289 free( p_state->p_next );
00290 p_state->p_next = NULL;
00291 }
00292 }
00293
00294 if( p_states )
00295 {
00296 msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_states );
00297 if( p_states->p_pic && p_states->p_pic->p_data_orig )
00298 free( p_states->p_pic->p_data_orig );
00299 if( p_states->p_pic ) free( p_states->p_pic );
00300 p_states->p_pic = NULL;
00301 if( p_state->psz_state ) free( p_state->psz_state );
00302 p_state->psz_state = NULL;
00303 free( p_states );
00304 p_states = NULL;
00305 }
00306 }
00307
00308
00309
00310
00311 int osd_ConfigLoader( vlc_object_t *p_this, const char *psz_file,
00312 osd_menu_t **p_menu )
00313 {
00314 osd_button_t *p_current = NULL;
00315 osd_button_t *p_prev = NULL;
00316
00317 #define MAX_FILE_PATH 256
00318 FILE *fd = NULL;
00319 int result = 0;
00320
00321 msg_Dbg( p_this, "opening osd definition file %s", psz_file );
00322 fd = fopen( psz_file, "r" );
00323 if( !fd )
00324 {
00325 msg_Err( p_this, "failed opening osd definition file %s", psz_file );
00326 return VLC_EGENERIC;
00327 }
00328
00329
00330 if( !feof( fd ) )
00331 {
00332 char action[25] = "";
00333 char path[MAX_FILE_PATH] = "";
00334 char *psz_path = NULL;
00335 size_t i_len = 0;
00336
00337
00338 psz_path = config_GetPsz( p_this, "osdmenu-file-path" );
00339 if( psz_path == NULL )
00340 {
00341 result = fscanf(fd, "%24s %255s", &action[0], &path[0] );
00342 }
00343 else
00344 {
00345
00346
00347
00348 strncpy( &path[0], psz_path, MAX_FILE_PATH );
00349 free( psz_path );
00350 psz_path = NULL;
00351 }
00352
00353 path[MAX_FILE_PATH-1] = '\0';
00354 i_len = strlen(&path[0]);
00355 if( i_len == MAX_FILE_PATH )
00356 i_len--;
00357 #if defined(WIN32) || defined(UNDER_CE)
00358 if( (i_len > 0) && path[i_len] != '\\' )
00359 path[i_len] = '\\';
00360 #else
00361 if( (i_len > 0) && path[i_len] != '/' )
00362 path[i_len] = '/';
00363 #endif
00364 path[i_len+1] = '\0';
00365 if( result == 0 || result == EOF )
00366 goto error;
00367 msg_Dbg( p_this, "%s=%s", &action[0], &path[0] );
00368
00369 if( i_len == 0 )
00370 *p_menu = osd_MenuNew( *p_menu, NULL, 0, 0 );
00371 else
00372 *p_menu = osd_MenuNew( *p_menu, &path[0], 0, 0 );
00373 }
00374
00375 if( !*p_menu )
00376 goto error;
00377
00378
00379 while( !feof( fd ) )
00380 {
00381 osd_state_t *p_state_current = NULL;
00382 osd_state_t *p_state_prev = NULL;
00383
00384 char cmd[25] = "";
00385 char action[25] = "";
00386 char state[25] = "";
00387 char file[256] = "";
00388 char path[512] = "";
00389 int i_x = 0;
00390 int i_y = 0;
00391
00392 result = fscanf( fd, "%24s %24s (%d,%d)", &cmd[0], &action[0], &i_x, &i_y );
00393 if( result == 0 )
00394 goto error;
00395 if( strncmp( &cmd[0], "action", 6 ) != 0 )
00396 break;
00397 msg_Dbg( p_this, " + %s hotkey=%s (%d,%d)", &cmd[0], &action[0], i_x, i_y );
00398
00399 p_prev = p_current;
00400 p_current = osd_ButtonNew( &action[0], i_x, i_y );
00401 if( !p_current )
00402 goto error;
00403
00404 if( p_prev )
00405 p_prev->p_next = p_current;
00406 else
00407 (*p_menu)->p_button = p_current;
00408 p_current->p_prev = p_prev;
00409
00410
00411 while( !feof( fd ) )
00412 {
00413 char type[25] = "";
00414
00415 result = fscanf( fd, "\t%24s", &state[0] );
00416 if( result == 0 )
00417 goto error;
00418
00419
00420 if( strncmp( &state[0], "action", 6 ) == 0 )
00421 {
00422 osd_button_t *p_up = NULL;
00423
00424 result = fscanf( fd, "%24s (%d,%d)", &action[0], &i_x, &i_y );
00425 if( result == 0 )
00426 goto error;
00427
00428 p_up = osd_ButtonNew( &action[0], i_x, i_y );
00429 if( !p_up )
00430 goto error;
00431
00432 p_up->p_down = p_current;
00433 p_current->p_up = p_up;
00434 msg_Dbg( p_this, " + (menu up) hotkey=%s (%d,%d)", &action[0], i_x, i_y );
00435
00436 result = fscanf( fd, "\t%24s %24s", &cmd[0], &type[0] );
00437 if( result == 0 )
00438 goto error;
00439 if( strncmp( &cmd[0], "type", 4 ) == 0 )
00440 {
00441 if( strncmp( &type[0], "volume", 6 ) == 0 )
00442 {
00443 (*p_menu)->p_state->p_volume = p_up;
00444 msg_Dbg( p_this, " + type=%s", &type[0] );
00445 }
00446 }
00447
00448 result = fscanf( fd, "\t%24s", &state[0] );
00449 if( result == 0 )
00450 goto error;
00451
00452 if( strncmp( &state[0], "range", 5 ) == 0 )
00453 {
00454 osd_state_t *p_range_current = NULL;
00455 osd_state_t *p_range_prev = NULL;
00456 int i_index = 0;
00457
00458 p_up->b_range = VLC_TRUE;
00459
00460 result = fscanf( fd, "\t%24s", &action[0] );
00461 if( result == 0 )
00462 goto error;
00463
00464 result = fscanf( fd, "\t%d", &i_index );
00465 if( result == 0 )
00466 goto error;
00467
00468 msg_Dbg( p_this, " + (menu up) hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );
00469
00470 if( p_up->psz_action_down ) free( p_up->psz_action_down );
00471 p_up->psz_action_down = strdup( &action[0] );
00472
00473
00474
00475
00476
00477
00478
00479
00480 while( !feof( fd ) )
00481 {
00482 result = fscanf( fd, "\t%255s", &file[0] );
00483 if( result == 0 )
00484 goto error;
00485 if( strncmp( &file[0], "end", 3 ) == 0 )
00486 break;
00487
00488 p_range_prev = p_range_current;
00489
00490 if( (*p_menu)->psz_path )
00491 {
00492 size_t i_path_size = strlen( (*p_menu)->psz_path );
00493 size_t i_file_size = strlen( &file[0] );
00494
00495 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
00496 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
00497 path[ i_path_size + i_file_size ] = '\0';
00498
00499 p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
00500 }
00501 else
00502 p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
00503
00504 if( !p_range_current || !p_range_current->p_pic )
00505 goto error;
00506
00507
00508 p_up->i_ranges++;
00509
00510 if( p_range_prev )
00511 p_range_prev->p_next = p_range_current;
00512 else
00513 p_up->p_states = p_range_current;
00514 p_range_current->p_prev = p_range_prev;
00515
00516 msg_Dbg( p_this, " |- range=%d, file=%s%s",
00517 p_up->i_ranges,
00518 (*p_menu)->psz_path, &file[0] );
00519 }
00520 if( i_index > 0 )
00521 {
00522 osd_state_t *p_range = NULL;
00523
00524
00525 p_range = p_up->p_states;
00526 while( (--i_index > 0) && p_range->p_next )
00527 {
00528 osd_state_t *p_temp = NULL;
00529 p_temp = p_range->p_next;
00530 p_range = p_temp;
00531 }
00532 p_up->p_current_state = p_range;
00533 }
00534 else p_up->p_current_state = p_up->p_states;
00535
00536 }
00537 result = fscanf( fd, "\t%24s", &state[0] );
00538 if( result == 0 )
00539 goto error;
00540 if( strncmp( &state[0], "end", 3 ) != 0 )
00541 goto error;
00542
00543
00544 continue;
00545 }
00546
00547
00548 if( strncmp( &state[0], "range", 5 ) == 0 )
00549 {
00550 osd_state_t *p_range_current = NULL;
00551 osd_state_t *p_range_prev = NULL;
00552 int i_index = 0;
00553
00554 p_current->b_range = VLC_TRUE;
00555
00556 result = fscanf( fd, "\t%24s", &action[0] );
00557 if( result == 0 )
00558 goto error;
00559
00560 result = fscanf( fd, "\t%d", &i_index );
00561 if( result == 0 )
00562 goto error;
00563
00564 msg_Dbg( p_this, " + hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );
00565 if( p_current->psz_action_down ) free( p_current->psz_action_down );
00566 p_current->psz_action_down = strdup( &action[0] );
00567
00568
00569
00570
00571
00572
00573
00574
00575 while( !feof( fd ) )
00576 {
00577 result = fscanf( fd, "\t%255s", &file[0] );
00578 if( result == 0 )
00579 goto error;
00580 if( strncmp( &file[0], "end", 3 ) == 0 )
00581 break;
00582
00583 p_range_prev = p_range_current;
00584
00585 if( (*p_menu)->psz_path )
00586 {
00587 size_t i_path_size = strlen( (*p_menu)->psz_path );
00588 size_t i_file_size = strlen( &file[0] );
00589
00590 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
00591 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
00592 path[ i_path_size + i_file_size ] = '\0';
00593
00594 p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
00595 }
00596 else
00597 p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
00598
00599 if( !p_range_current || !p_range_current->p_pic )
00600 goto error;
00601
00602
00603 p_current->i_ranges++;
00604
00605 if( p_range_prev )
00606 p_range_prev->p_next = p_range_current;
00607 else
00608 p_current->p_states = p_range_current;
00609 p_range_current->p_prev = p_range_prev;
00610
00611 msg_Dbg( p_this, " |- range=%d, file=%s%s",
00612 p_current->i_ranges,
00613 (*p_menu)->psz_path, &file[0] );
00614 }
00615 if( i_index > 0 )
00616 {
00617 osd_state_t *p_range = NULL;
00618
00619
00620 p_range = p_current->p_states;
00621 while( (--i_index > 0) && p_range->p_next )
00622 {
00623 osd_state_t *p_temp = NULL;
00624 p_temp = p_range->p_next;
00625 p_range = p_temp;
00626 }
00627 p_current->p_current_state = p_range;
00628 }
00629 else p_current->p_current_state = p_current->p_states;
00630
00631 continue;
00632 }
00633 if( strncmp( &state[0], "end", 3 ) == 0 )
00634 break;
00635
00636 result = fscanf( fd, "\t%255s", &file[0] );
00637 if( result == 0 )
00638 goto error;
00639
00640 p_state_prev = p_state_current;
00641
00642 if( ( strncmp( ppsz_button_states[0], &state[0], strlen(ppsz_button_states[0]) ) != 0 ) &&
00643 ( strncmp( ppsz_button_states[1], &state[0], strlen(ppsz_button_states[1]) ) != 0 ) &&
00644 ( strncmp( ppsz_button_states[2], &state[0], strlen(ppsz_button_states[2]) ) != 0 ) )
00645 {
00646 msg_Err( p_this, "invalid button state %s for button %s expected %d: unselect, select or pressed)",
00647 &state[0], &action[0], strlen(&state[0]));
00648 goto error;
00649 }
00650
00651 if( (*p_menu)->psz_path )
00652 {
00653 size_t i_path_size = strlen( (*p_menu)->psz_path );
00654 size_t i_file_size = strlen( &file[0] );
00655
00656 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
00657 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
00658 path[ i_path_size + i_file_size ] = '\0';
00659
00660 p_state_current = osd_StateNew( p_this, &path[0], &state[0] );
00661 }
00662 else
00663 p_state_current = osd_StateNew( p_this, &file[0], &state[0] );
00664
00665 if( !p_state_current || !p_state_current->p_pic )
00666 goto error;
00667
00668 if( p_state_prev )
00669 p_state_prev->p_next = p_state_current;
00670 else
00671 p_current->p_states = p_state_current;
00672 p_state_current->p_prev = p_state_prev;
00673
00674 msg_Dbg( p_this, " |- state=%s, file=%s%s", &state[0], (*p_menu)->psz_path, &file[0] );
00675 }
00676 p_current->p_current_state = p_current->p_states;
00677 }
00678
00679
00680
00681
00682 p_current = (*p_menu)->p_button;
00683 while( p_current && p_current->p_next )
00684 {
00685 osd_button_t *p_temp = NULL;
00686 p_temp = p_current->p_next;
00687 p_current = p_temp;
00688 }
00689 (*p_menu)->p_last_button = p_current;
00690 fclose( fd );
00691 return 0;
00692
00693 #undef MAX_FILE_PATH
00694 error:
00695 msg_Err( p_this, "parsing file failed (returned %d)", result );
00696 fclose( fd );
00697 return 1;
00698 }
00699
00700
00701
00702
00703 void osd_ConfigUnload( vlc_object_t *p_this, osd_menu_t **p_osd)
00704 {
00705 msg_Dbg( p_this, "unloading OSD menu structure" );
00706 osd_MenuFree( p_this, *p_osd );
00707 }