1 /*****************************************************************************
\r
2 * osd_parser.c - The OSD Menu parser core code.
\r
3 *****************************************************************************
\r
4 * Copyright (C) 2005 M2X
\r
5 * $Id: osd_parser.c 9451 2004-12-01 01:07:08Z jpsaman $
\r
7 * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
\r
9 * This program is free software; you can redistribute it and/or modify
\r
10 * it under the terms of the GNU General Public License as published by
\r
11 * the Free Software Foundation; either version 2 of the License, or
\r
12 * (at your option) any later version.
\r
14 * This program is distributed in the hope that it will be useful,
\r
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
17 * GNU General Public License for more details.
\r
19 * You should have received a copy of the GNU General Public License
\r
20 * along with this program; if not, write to the Free Software
\r
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
\r
22 *****************************************************************************/
\r
24 /*****************************************************************************
\r
26 *****************************************************************************/
\r
30 #include <vlc/vlc.h>
\r
31 #include <vlc_config.h>
\r
32 //#include <vlc_es.h>
\r
33 #include <vlc_video.h>
\r
35 #include <vlc_keys.h>
\r
36 #include <vlc_image.h>
\r
37 #include <vlc_osd.h>
\r
40 #undef OSD_MENU_DEBUG
\r
42 /*****************************************************************************
\r
44 *****************************************************************************/
\r
45 static const char *ppsz_button_states[] = { "unselect", "select", "pressed" };
\r
47 /* OSD Menu structure support routines */
\r
48 static osd_menu_t *osd_MenuNew( osd_menu_t *, const char *, int, int );
\r
49 static osd_button_t *osd_ButtonNew( const char *, int, int );
\r
50 static osd_state_t *osd_StateNew( vlc_object_t *, const char *, const char * );
\r
52 static void osd_MenuFree ( vlc_object_t *, osd_menu_t * );
\r
53 static void osd_ButtonFree( vlc_object_t *, osd_button_t * );
\r
54 static void osd_StatesFree( vlc_object_t *, osd_state_t * );
\r
56 static picture_t *osd_LoadImage( vlc_object_t *, const char *);
\r
59 /*****************************************************************************
\r
61 *****************************************************************************/
\r
62 static picture_t *osd_YuvaYuvp( vlc_object_t *p_this, picture_t *p_picture )
\r
64 video_format_t *p_fmt = NULL;
\r
65 int i = 0, j = 0, n = 0, p = 0;
\r
66 int i_max_entries = 256;
\r
68 #ifdef RANDOM_DITHERING
\r
69 int i_seed = 0xdeadbeef; /* random seed */
\r
71 int *pi_delta = NULL;
\r
73 int i_pixels = p_picture->p[0].i_visible_lines
\r
74 * p_picture->p[0].i_pitch;
\r
75 int i_iterator = p_picture->p[0].i_visible_lines * 3 / 4
\r
76 * p_picture->p[0].i_pitch
\r
77 + p_picture->p[0].i_pitch * 1 / 3;
\r
78 int i_tolerance = 0;
\r
80 p_fmt = (video_format_t*) malloc( sizeof( video_format_t ) );
\r
83 msg_Err( p_this, "couldn't allocate video_format_t ... aborting YUVA to YUVP conversion of picture" );
\r
86 p_fmt->i_chroma = VLC_FOURCC('Y','U','V','P');
\r
87 p_fmt->p_palette = (video_palette_t *) malloc( sizeof( video_palette_t ) );
\r
88 if( !p_fmt->p_palette )
\r
90 msg_Err( p_this, "couldn't allocate video_palette_t ... aborting YUVA to YUVP conversion of picture" );
\r
94 p_fmt->p_palette->i_entries = 0;
\r
96 /* Find best iterator using Euclide’s algorithm */
\r
97 for( ; i_iterator > 1 ; i_iterator-- )
\r
100 int b = i_iterator;
\r
116 /* Count colors, build best palette */
\r
117 for( i_tolerance = 0; i_tolerance < 128; i_tolerance++ )
\r
119 vlc_bool_t b_success = VLC_TRUE;
\r
120 p_fmt->p_palette->i_entries = 0;
\r
122 for( i = 0; i < i_pixels ; )
\r
124 uint8_t y = 0, u = 0, v = 0, a = 0;
\r
125 y = p_picture->p[0].p_pixels[i];
\r
126 u = p_picture->p[1].p_pixels[i];
\r
127 v = p_picture->p[2].p_pixels[i];
\r
128 a = p_picture->p[3].p_pixels[i];
\r
129 for( j = 0; j < p_fmt->p_palette->i_entries; j++ )
\r
131 if( abs((int)p_fmt->p_palette->palette[j][0] - (int)y) <= i_tolerance &&
\r
132 abs((int)p_fmt->p_palette->palette[j][1] - (int)u) <= i_tolerance &&
\r
133 abs((int)p_fmt->p_palette->palette[j][2] - (int)v) <= i_tolerance &&
\r
134 abs((int)p_fmt->p_palette->palette[j][3] - (int)a) <= i_tolerance / 2 )
\r
139 if( j == p_fmt->p_palette->i_entries )
\r
141 p_fmt->p_palette->palette[j][0] = y;
\r
142 p_fmt->p_palette->palette[j][1] = u;
\r
143 p_fmt->p_palette->palette[j][2] = v;
\r
144 p_fmt->p_palette->palette[j][3] = a;
\r
145 p_fmt->p_palette->i_entries++;
\r
147 if( p_fmt->p_palette->i_entries >= i_max_entries )
\r
149 b_success = VLC_FALSE;
\r
166 msg_Dbg( p_this, "best palette has %d colors", p_fmt->p_palette->i_entries );
\r
169 #ifndef RANDOM_DITHERING
\r
170 pi_delta = malloc( ( p_picture->p[0].i_pitch + 1 ) * sizeof(int) * 4 );
\r
173 msg_Err( p_this, "couldn't allocate video_palette_t ... aborting YUVA to YUVP conversion of picture" );
\r
174 free( p_fmt->p_palette );
\r
179 for( i = 0; i < (p_picture->p[0].i_pitch + 1) * 4 ; i++ )
\r
185 /* Fill image with our new colours */
\r
186 for( p = 0; p < p_picture->p[0].i_visible_lines ; p++ )
\r
188 int i_ydelta = 0, i_udelta = 0, i_vdelta = 0, i_adelta = 0;
\r
190 for( n = 0; n < p_picture->p[0].i_pitch ; n++ )
\r
192 int i_offset = p * p_picture->p[0].i_pitch + n;
\r
194 int i_mindist, i_best;
\r
196 y = (int)p_picture->p[0].p_pixels[i_offset];
\r
197 u = (int)p_picture->p[1].p_pixels[i_offset];
\r
198 v = (int)p_picture->p[2].p_pixels[i_offset];
\r
199 a = (int)p_picture->p[3].p_pixels[i_offset];
\r
201 /* Add dithering compensation */
\r
202 #ifdef RANDOM_DITHERING
\r
203 y += ((i_seed & 0xff) - 0x80) * i_tolerance / 0x80;
\r
204 u += (((i_seed >> 8) & 0xff) - 0x80) * i_tolerance / 0x80;
\r
205 v += (((i_seed >> 16) & 0xff) - 0x80) * i_tolerance / 0x80;
\r
206 a += (((i_seed >> 24) & 0xff) - 0x80) * i_tolerance / 0x80;
\r
208 y += i_ydelta + pi_delta[ n * 4 ];
\r
209 u += i_udelta + pi_delta[ n * 4 + 1 ];
\r
210 v += i_vdelta + pi_delta[ n * 4 + 2 ];
\r
211 a += i_adelta + pi_delta[ n * 4 + 3 ];
\r
214 /* Find best colour in palette */
\r
215 for( i_mindist = 99999999, i_best = 0, j = 0; j < p_fmt->p_palette->i_entries; j++ )
\r
219 i_dist += abs((int)p_fmt->p_palette->palette[j][0] - y);
\r
220 i_dist += abs((int)p_fmt->p_palette->palette[j][1] - u);
\r
221 i_dist += abs((int)p_fmt->p_palette->palette[j][2] - v);
\r
222 i_dist += 2 * abs((int)p_fmt->p_palette->palette[j][3] - a);
\r
224 if( i_dist < i_mindist )
\r
226 i_mindist = i_dist;
\r
231 /* Set pixel to best color */
\r
232 p_picture->p[0].p_pixels[i_offset] = i_best;
\r
234 /* Update dithering state */
\r
235 #ifdef RANDOM_DITHERING
\r
236 i_seed = (i_seed * 0x1283837) ^ 0x789479 ^ (i_seed >> 13);
\r
238 i_ydelta = y - (int)p_fmt->p_palette->palette[i_best][0];
\r
239 i_udelta = u - (int)p_fmt->p_palette->palette[i_best][1];
\r
240 i_vdelta = v - (int)p_fmt->p_palette->palette[i_best][2];
\r
241 i_adelta = a - (int)p_fmt->p_palette->palette[i_best][3];
\r
242 pi_delta[ n * 4 ] = i_ydelta * 3 / 8;
\r
243 pi_delta[ n * 4 + 1 ] = i_udelta * 3 / 8;
\r
244 pi_delta[ n * 4 + 2 ] = i_vdelta * 3 / 8;
\r
245 pi_delta[ n * 4 + 3 ] = i_adelta * 3 / 8;
\r
246 i_ydelta = i_ydelta * 5 / 8;
\r
247 i_udelta = i_udelta * 5 / 8;
\r
248 i_vdelta = i_vdelta * 5 / 8;
\r
249 i_adelta = i_adelta * 5 / 8;
\r
254 #ifndef RANDOM_DITHERING
\r
259 for( i = p_fmt->p_palette->i_entries; i < i_max_entries; i++ )
\r
261 p_fmt->p_palette->palette[i][0] = 0;
\r
262 p_fmt->p_palette->palette[i][1] = 0;
\r
263 p_fmt->p_palette->palette[i][2] = 0;
\r
264 p_fmt->p_palette->palette[i][3] = 0;
\r
266 p_fmt->p_palette->i_entries = i_max_entries;
\r
268 msg_Dbg( p_this, "best palette has %d colors", p_fmt->p_palette->i_entries );
\r
271 p_picture->format.i_chroma = VLC_FOURCC('Y','U','V','P');
\r
272 if( p_picture->format.p_palette )
\r
273 free( p_picture->format.p_palette );
\r
274 p_picture->format.p_palette = p_fmt->p_palette;
\r
279 /*****************************************************************************
\r
280 * osd_LoadImage: loads the logo image into memory
\r
281 *****************************************************************************/
\r
282 static picture_t *osd_LoadImage( vlc_object_t *p_this, const char *psz_filename )
\r
284 picture_t *p_pic = NULL;
\r
285 image_handler_t *p_image;
\r
286 video_format_t fmt_in = {0}, fmt_out = {0};
\r
288 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
\r
289 p_image = image_HandlerCreate( p_this );
\r
292 p_pic = image_ReadUrl( p_image, psz_filename, &fmt_in, &fmt_out );
\r
293 image_HandlerDelete( p_image );
\r
295 p_pic = osd_YuvaYuvp( p_this, p_pic );
\r
298 else msg_Err( p_this, "unable to handle this chroma" );
\r
303 /*****************************************************************************
\r
304 * Create a new Menu structure
\r
305 *****************************************************************************/
\r
306 static osd_menu_t *osd_MenuNew( osd_menu_t *p_menu, const char *psz_path, int i_x, int i_y )
\r
308 if( !p_menu ) return NULL;
\r
310 p_menu->p_state = (osd_menu_state_t *) malloc( sizeof( osd_menu_state_t ) );
\r
311 if( !p_menu->p_state )
\r
312 msg_Err( p_menu, "memory allocation for OSD Menu state failed." );
\r
314 if( psz_path != NULL )
\r
315 p_menu->psz_path = strdup( psz_path );
\r
317 p_menu->psz_path = NULL;
\r
324 /*****************************************************************************
\r
326 *****************************************************************************/
\r
327 static void osd_MenuFree( vlc_object_t *p_this, osd_menu_t *p_menu )
\r
329 msg_Dbg( p_this, "freeing menu" );
\r
330 osd_ButtonFree( p_this, p_menu->p_button );
\r
331 p_menu->p_button = NULL;
\r
332 p_menu->p_last_button = NULL;
\r
333 if( p_menu->psz_path ) free( p_menu->psz_path );
\r
334 p_menu->psz_path = NULL;
\r
335 if( p_menu->p_state ) free( p_menu->p_state );
\r
336 p_menu->p_state = NULL;
\r
339 /*****************************************************************************
\r
340 * Create a new button
\r
341 *****************************************************************************/
\r
342 static osd_button_t *osd_ButtonNew( const char *psz_action, int i_x, int i_y )
\r
344 osd_button_t *p_button = NULL;
\r
345 p_button = (osd_button_t*) malloc( sizeof(osd_button_t) );
\r
349 memset( p_button, 0, sizeof(osd_button_t) );
\r
350 p_button->psz_action = strdup(psz_action);
\r
351 p_button->psz_action_down = NULL;
\r
352 p_button->p_feedback = NULL;
\r
353 p_button->i_x = i_x;
\r
354 p_button->i_y = i_y;
\r
359 /*****************************************************************************
\r
361 *****************************************************************************/
\r
362 static void osd_ButtonFree( vlc_object_t *p_this, osd_button_t *p_button )
\r
364 osd_button_t *p_current = p_button;
\r
365 osd_button_t *p_next = NULL;
\r
366 osd_button_t *p_prev = NULL;
\r
368 /* First walk to the end. */
\r
369 while( p_current->p_next )
\r
371 p_next = p_current->p_next;
\r
372 p_current = p_next;
\r
374 /* Then free end first and walk to the start. */
\r
375 while( p_current->p_prev )
\r
377 msg_Dbg( p_this, "+ freeing button %s [%p]", p_current->psz_action, p_current );
\r
378 p_prev = p_current->p_prev;
\r
379 p_current = p_prev;
\r
380 if( p_current->p_next )
\r
382 if( p_current->p_next->psz_name )
\r
383 free( p_current->p_next->psz_name );
\r
384 if( p_current->p_next->psz_action )
\r
385 free( p_current->p_next->psz_action );
\r
386 if( p_current->p_next->psz_action_down )
\r
387 free( p_current->p_next->psz_action_down );
\r
388 if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
\r
389 free( p_current->p_feedback->p_data_orig );
\r
390 if( p_current->p_feedback )
\r
391 free( p_current->p_feedback );
\r
393 p_current->p_next->psz_action_down = NULL;
\r
394 p_current->p_next->psz_action = NULL;
\r
395 p_current->p_next->psz_name = NULL;
\r
396 p_current->p_feedback = NULL;
\r
398 /* Free all states first */
\r
399 if( p_current->p_next->p_states )
\r
400 osd_StatesFree( p_this, p_current->p_next->p_states );
\r
401 p_current->p_next->p_states = NULL;
\r
402 if( p_current->p_next) free( p_current->p_next );
\r
403 p_current->p_next = NULL;
\r
406 if( p_current->p_up )
\r
408 if( p_current->p_up->psz_name )
\r
409 free( p_current->p_up->psz_name );
\r
410 if( p_current->p_up->psz_action )
\r
411 free( p_current->p_up->psz_action );
\r
412 if( p_current->p_up->psz_action_down )
\r
413 free( p_current->p_up->psz_action_down );
\r
414 if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
\r
415 free( p_current->p_feedback->p_data_orig );
\r
416 if( p_current->p_feedback )
\r
417 free( p_current->p_feedback );
\r
419 p_current->p_up->psz_action_down = NULL;
\r
420 p_current->p_up->psz_action = NULL;
\r
421 p_current->p_up->psz_name = NULL;
\r
422 p_current->p_feedback = NULL;
\r
424 /* Free all states first */
\r
425 if( p_current->p_up->p_states )
\r
426 osd_StatesFree( p_this, p_current->p_up->p_states );
\r
427 p_current->p_up->p_states = NULL;
\r
428 if( p_current->p_up ) free( p_current->p_up );
\r
429 p_current->p_up = NULL;
\r
432 /* Free the last one. */
\r
435 msg_Dbg( p_this, "+ freeing button %s [%p]", p_button->psz_action, p_button );
\r
436 if( p_button->psz_name ) free( p_button->psz_name );
\r
437 if( p_button->psz_action ) free( p_button->psz_action );
\r
438 if( p_button->psz_action_down ) free( p_button->psz_action_down );
\r
439 if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
\r
440 free( p_current->p_feedback->p_data_orig );
\r
441 if( p_current->p_feedback )
\r
442 free( p_current->p_feedback );
\r
444 p_button->psz_name = NULL;
\r
445 p_button->psz_action = NULL;
\r
446 p_button->psz_action_down = NULL;
\r
447 p_current->p_feedback = NULL;
\r
449 if( p_button->p_states )
\r
450 osd_StatesFree( p_this, p_button->p_states );
\r
451 p_button->p_states = NULL;
\r
457 /*****************************************************************************
\r
458 * Create a new state image
\r
459 *****************************************************************************/
\r
460 static osd_state_t *osd_StateNew( vlc_object_t *p_this, const char *psz_file, const char *psz_state )
\r
462 osd_state_t *p_state = NULL;
\r
463 p_state = (osd_state_t*) malloc( sizeof(osd_state_t) );
\r
467 memset( p_state, 0, sizeof(osd_state_t) );
\r
468 p_state->p_pic = osd_LoadImage( p_this, psz_file );
\r
472 p_state->psz_state = strdup( psz_state );
\r
473 if( strncmp( ppsz_button_states[0], psz_state, strlen(ppsz_button_states[0]) ) == 0 )
\r
474 p_state->i_state = OSD_BUTTON_UNSELECT;
\r
475 else if( strncmp( ppsz_button_states[1], psz_state, strlen(ppsz_button_states[1]) ) == 0 )
\r
476 p_state->i_state = OSD_BUTTON_SELECT;
\r
477 else if( strncmp( ppsz_button_states[2], psz_state, strlen(ppsz_button_states[2]) ) == 0 )
\r
478 p_state->i_state = OSD_BUTTON_PRESSED;
\r
483 /*****************************************************************************
\r
484 * Free state images
\r
485 *****************************************************************************/
\r
486 static void osd_StatesFree( vlc_object_t *p_this, osd_state_t *p_states )
\r
488 osd_state_t *p_state = p_states;
\r
489 osd_state_t *p_next = NULL;
\r
490 osd_state_t *p_prev = NULL;
\r
492 while( p_state->p_next )
\r
494 p_next = p_state->p_next;
\r
497 /* Then free end first and walk to the start. */
\r
498 while( p_state->p_prev )
\r
500 msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_state );
\r
501 p_prev = p_state->p_prev;
\r
503 if( p_state->p_next )
\r
505 if( p_state->p_next->p_pic && p_state->p_next->p_pic->p_data_orig )
\r
506 free( p_state->p_next->p_pic->p_data_orig );
\r
507 if( p_state->p_next->p_pic ) free( p_state->p_next->p_pic );
\r
508 p_state->p_next->p_pic = NULL;
\r
509 if( p_state->p_next->psz_state ) free( p_state->p_next->psz_state );
\r
510 p_state->p_next->psz_state = NULL;
\r
511 free( p_state->p_next );
\r
512 p_state->p_next = NULL;
\r
515 /* Free the last one. */
\r
518 msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_states );
\r
519 if( p_states->p_pic && p_states->p_pic->p_data_orig )
\r
520 free( p_states->p_pic->p_data_orig );
\r
521 if( p_states->p_pic ) free( p_states->p_pic );
\r
522 p_states->p_pic = NULL;
\r
523 if( p_state->psz_state ) free( p_state->psz_state );
\r
524 p_state->psz_state = NULL;
\r
530 /*****************************************************************************
\r
531 * osd_ConfigLoader: Load and parse osd text configurationfile
\r
532 *****************************************************************************/
\r
533 int osd_ConfigLoader( vlc_object_t *p_this, const char *psz_file,
\r
534 osd_menu_t **p_menu )
\r
536 osd_button_t *p_current = NULL; /* button currently processed */
\r
537 osd_button_t *p_prev = NULL; /* previous processed button */
\r
539 #define MAX_FILE_PATH 256
\r
543 msg_Dbg( p_this, "opening osd definition file %s", psz_file );
\r
544 fd = fopen( psz_file, "r" );
\r
547 msg_Err( p_this, "failed opening osd definition file %s", psz_file );
\r
548 return VLC_EGENERIC;
\r
551 /* Read first line */
\r
554 char action[25] = "";
\r
555 char path[MAX_FILE_PATH] = "";
\r
556 char *psz_path = NULL;
\r
559 /* override images path ? */
\r
560 psz_path = config_GetPsz( p_this, "osdmenu-file-path" );
\r
561 if( psz_path == NULL )
\r
563 result = fscanf(fd, "%24s %255s", &action[0], &path[0] );
\r
567 /* psz_path is not null and therefor &path[0] cannot be NULL
\r
568 * it might be null terminated.
\r
570 strncpy( &path[0], psz_path, MAX_FILE_PATH );
\r
574 /* NULL terminate before asking the length of path[] */
\r
575 path[MAX_FILE_PATH-1] = '\0';
\r
576 i_len = strlen(&path[0]);
\r
577 if( i_len == MAX_FILE_PATH )
\r
578 i_len--; /* truncate to prevent buffer overflow */
\r
579 #if defined(WIN32) || defined(UNDER_CE)
\r
580 if( (i_len > 0) && path[i_len] != '\\' )
\r
581 path[i_len] = '\\';
\r
583 if( (i_len > 0) && path[i_len] != '/' )
\r
586 path[i_len+1] = '\0';
\r
587 if( result == 0 || result == EOF )
\r
589 msg_Dbg( p_this, "%s=%s", &action[0], &path[0] );
\r
592 *p_menu = osd_MenuNew( *p_menu, NULL, 0, 0 );
\r
594 *p_menu = osd_MenuNew( *p_menu, &path[0], 0, 0 );
\r
600 /* read successive lines */
\r
601 while( !feof( fd ) )
\r
603 osd_state_t *p_state_current = NULL; /* button state currently processed */
\r
604 osd_state_t *p_state_prev = NULL; /* previous state processed button */
\r
606 char cmd[25] = "";
\r
607 char action[25] = "";
\r
608 char state[25] = "";
\r
609 char file[256] = "";
\r
610 char path[512] = "";
\r
614 result = fscanf( fd, "%24s %24s (%d,%d)", &cmd[0], &action[0], &i_x, &i_y );
\r
617 if( strncmp( &cmd[0], "action", 6 ) != 0 )
\r
619 msg_Dbg( p_this, " + %s hotkey=%s (%d,%d)", &cmd[0], &action[0], i_x, i_y );
\r
621 p_prev = p_current;
\r
622 p_current = osd_ButtonNew( &action[0], i_x, i_y );
\r
627 p_prev->p_next = p_current;
\r
629 (*p_menu)->p_button = p_current;
\r
630 p_current->p_prev = p_prev;
\r
632 /* parse all states */
\r
633 while( !feof( fd ) )
\r
635 char type[25] = "";
\r
637 result = fscanf( fd, "\t%24s", &state[0] );
\r
641 /* FIXME: We only parse one level deep now */
\r
642 if( strncmp( &state[0], "action", 6 ) == 0 )
\r
644 osd_button_t *p_up = NULL;
\r
646 result = fscanf( fd, "%24s (%d,%d)", &action[0], &i_x, &i_y );
\r
649 /* create new button */
\r
650 p_up = osd_ButtonNew( &action[0], i_x, i_y );
\r
653 /* Link to list */
\r
654 p_up->p_down = p_current;
\r
655 p_current->p_up = p_up;
\r
656 msg_Dbg( p_this, " + (menu up) hotkey=%s (%d,%d)", &action[0], i_x, i_y );
\r
657 /* Parse type state */
\r
658 result = fscanf( fd, "\t%24s %24s", &cmd[0], &type[0] );
\r
661 if( strncmp( &cmd[0], "type", 4 ) == 0 )
\r
663 if( strncmp( &type[0], "volume", 6 ) == 0 )
\r
665 (*p_menu)->p_state->p_volume = p_up;
\r
666 msg_Dbg( p_this, " + type=%s", &type[0] );
\r
669 /* Parse range state */
\r
670 result = fscanf( fd, "\t%24s", &state[0] );
\r
673 /* Parse the range state */
\r
674 if( strncmp( &state[0], "range", 5 ) == 0 )
\r
676 osd_state_t *p_range_current = NULL; /* range state currently processed */
\r
677 osd_state_t *p_range_prev = NULL; /* previous state processed range */
\r
680 p_up->b_range = VLC_TRUE;
\r
682 result = fscanf( fd, "\t%24s", &action[0] );
\r
686 result = fscanf( fd, "\t%d", &i_index );
\r
690 msg_Dbg( p_this, " + (menu up) hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );
\r
692 if( p_up->psz_action_down ) free( p_up->psz_action_down );
\r
693 p_up->psz_action_down = strdup( &action[0] );
\r
695 /* Parse range contstruction :
\r
702 while( !feof( fd ) )
\r
704 result = fscanf( fd, "\t%255s", &file[0] );
\r
707 if( strncmp( &file[0], "end", 3 ) == 0 )
\r
710 p_range_prev = p_range_current;
\r
712 if( (*p_menu)->psz_path )
\r
714 size_t i_path_size = strlen( (*p_menu)->psz_path );
\r
715 size_t i_file_size = strlen( &file[0] );
\r
717 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
\r
718 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
\r
719 path[ i_path_size + i_file_size ] = '\0';
\r
721 p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
\r
723 else /* absolute paths are used. */
\r
724 p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
\r
726 if( !p_range_current || !p_range_current->p_pic )
\r
729 /* increment the number of ranges for this button */
\r
733 p_range_prev->p_next = p_range_current;
\r
735 p_up->p_states = p_range_current;
\r
736 p_range_current->p_prev = p_range_prev;
\r
738 msg_Dbg( p_this, " |- range=%d, file=%s%s",
\r
740 (*p_menu)->psz_path, &file[0] );
\r
744 osd_state_t *p_range = NULL;
\r
746 /* Find the default index for state range */
\r
747 p_range = p_up->p_states;
\r
748 while( (--i_index > 0) && p_range->p_next )
\r
750 osd_state_t *p_temp = NULL;
\r
751 p_temp = p_range->p_next;
\r
754 p_up->p_current_state = p_range;
\r
756 else p_up->p_current_state = p_up->p_states;
\r
759 result = fscanf( fd, "\t%24s", &state[0] );
\r
762 if( strncmp( &state[0], "end", 3 ) != 0 )
\r
765 /* Continue at the beginning of the while() */
\r
769 /* Parse the range state */
\r
770 if( strncmp( &state[0], "range", 5 ) == 0 )
\r
772 osd_state_t *p_range_current = NULL; /* range state currently processed */
\r
773 osd_state_t *p_range_prev = NULL; /* previous state processed range */
\r
776 p_current->b_range = VLC_TRUE;
\r
778 result = fscanf( fd, "\t%24s", &action[0] );
\r
782 result = fscanf( fd, "\t%d", &i_index );
\r
786 msg_Dbg( p_this, " + hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );
\r
787 if( p_current->psz_action_down ) free( p_current->psz_action_down );
\r
788 p_current->psz_action_down = strdup( &action[0] );
\r
790 /* Parse range contstruction :
\r
797 while( !feof( fd ) )
\r
799 result = fscanf( fd, "\t%255s", &file[0] );
\r
802 if( strncmp( &file[0], "end", 3 ) == 0 )
\r
805 p_range_prev = p_range_current;
\r
807 if( (*p_menu)->psz_path )
\r
809 size_t i_path_size = strlen( (*p_menu)->psz_path );
\r
810 size_t i_file_size = strlen( &file[0] );
\r
812 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
\r
813 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
\r
814 path[ i_path_size + i_file_size ] = '\0';
\r
816 p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
\r
818 else /* absolute paths are used. */
\r
819 p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
\r
821 if( !p_range_current || !p_range_current->p_pic )
\r
824 /* increment the number of ranges for this button */
\r
825 p_current->i_ranges++;
\r
828 p_range_prev->p_next = p_range_current;
\r
830 p_current->p_states = p_range_current;
\r
831 p_range_current->p_prev = p_range_prev;
\r
833 msg_Dbg( p_this, " |- range=%d, file=%s%s",
\r
834 p_current->i_ranges,
\r
835 (*p_menu)->psz_path, &file[0] );
\r
839 osd_state_t *p_range = NULL;
\r
841 /* Find the default index for state range */
\r
842 p_range = p_current->p_states;
\r
843 while( (--i_index > 0) && p_range->p_next )
\r
845 osd_state_t *p_temp = NULL;
\r
846 p_temp = p_range->p_next;
\r
849 p_current->p_current_state = p_range;
\r
851 else p_current->p_current_state = p_current->p_states;
\r
852 /* Continue at the beginning of the while() */
\r
855 if( strncmp( &state[0], "end", 3 ) == 0 )
\r
858 result = fscanf( fd, "\t%255s", &file[0] );
\r
862 p_state_prev = p_state_current;
\r
864 if( ( strncmp( ppsz_button_states[0], &state[0], strlen(ppsz_button_states[0]) ) != 0 ) &&
\r
865 ( strncmp( ppsz_button_states[1], &state[0], strlen(ppsz_button_states[1]) ) != 0 ) &&
\r
866 ( strncmp( ppsz_button_states[2], &state[0], strlen(ppsz_button_states[2]) ) != 0 ) )
\r
868 msg_Err( p_this, "invalid button state %s for button %s expected %d: unselect, select or pressed)",
\r
869 &state[0], &action[0], strlen(&state[0]));
\r
873 if( (*p_menu)->psz_path )
\r
875 size_t i_path_size = strlen( (*p_menu)->psz_path );
\r
876 size_t i_file_size = strlen( &file[0] );
\r
878 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
\r
879 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
\r
880 path[ i_path_size + i_file_size ] = '\0';
\r
882 p_state_current = osd_StateNew( p_this, &path[0], &state[0] );
\r
884 else /* absolute paths are used. */
\r
885 p_state_current = osd_StateNew( p_this, &file[0], &state[0] );
\r
887 if( !p_state_current || !p_state_current->p_pic )
\r
891 p_state_prev->p_next = p_state_current;
\r
893 p_current->p_states = p_state_current;
\r
894 p_state_current->p_prev = p_state_prev;
\r
896 msg_Dbg( p_this, " |- state=%s, file=%s%s", &state[0], (*p_menu)->psz_path, &file[0] );
\r
898 p_current->p_current_state = p_current->p_states;
\r
901 /* Find the last button and store its pointer.
\r
902 * The OSD menu behaves like a roundrobin list.
\r
904 p_current = (*p_menu)->p_button;
\r
905 while( p_current && p_current->p_next )
\r
907 osd_button_t *p_temp = NULL;
\r
908 p_temp = p_current->p_next;
\r
909 p_current = p_temp;
\r
911 (*p_menu)->p_last_button = p_current;
\r
915 #undef MAX_FILE_PATH
\r
917 msg_Err( p_this, "parsing file failed (returned %d)", result );
\r
922 /*****************************************************************************
\r
923 * osd_ConfigUnload: Load and parse osd text configurationfile
\r
924 *****************************************************************************/
\r
925 void osd_ConfigUnload( vlc_object_t *p_this, osd_menu_t **p_osd)
\r
927 msg_Dbg( p_this, "unloading OSD menu structure" );
\r
928 osd_MenuFree( p_this, *p_osd );
\r