]> git.sesse.net Git - vlc/blob - modules/access/cdda/info.c
* Protect input item's meta through setters and getters. That allows tracking of...
[vlc] / modules / access / cdda / info.c
1 /*****************************************************************************
2  * info.c : CD digital audio input information routines
3  *****************************************************************************
4  * Copyright (C) 2004, 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Rocky Bernstein <rocky@panix.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "callback.h"      /* FIXME - reorganize callback.h, cdda.h better */
28 #include "cdda.h"          /* private structures. Also #includes vlc things */
29 #include <vlc_playlist.h>  /* Has to come *after* cdda.h */
30
31 #include <cdio/cdio.h>
32 #include <cdio/cdtext.h>
33 #include <cdio/logging.h>
34 #include <cdio/cd_types.h>
35 #include "info.h"
36
37 #ifdef HAVE_ERRNO_H
38 #   include <errno.h>
39 #endif
40
41 static char *CDDAFormatStr( const access_t *p_access, cdda_data_t *p_cdda,
42                             const char format_str[], const char *psz_mrl, 
43                             track_t i_track);
44
45 static char *CDDAFormatMRL( const access_t *p_access, track_t i_track );
46
47 #ifdef HAVE_LIBCDDB
48
49 #define free_and_dup(var, val) \
50   if (var) free(var);          \
51   if (val) var=strdup(val);
52
53
54 /* Saves CDDB information about CD-DA via libcddb. */
55 static void 
56 GetCDDBInfo( access_t *p_access, cdda_data_t *p_cdda )
57 {
58     int i, i_matches;
59     cddb_conn_t  *conn = cddb_new();
60     const CdIo_t *p_cdio = p_cdda->p_cdio;
61
62     dbg_print( (INPUT_DBG_CALL), "" );
63
64 #ifdef FIXME_NOW
65     cddb_log_set_handler (uninit_log_handler);
66 #endif
67
68     if (!conn)
69     {
70         msg_Warn( p_access, "Unable to initialize libcddb" );
71         goto cddb_destroy;
72     }
73
74     cddb_set_email_address( conn,
75                             config_GetPsz( p_access,
76                                            MODULE_STRING "-cddb-email") );
77     cddb_set_server_name( conn,
78                           config_GetPsz( p_access,
79                                          MODULE_STRING "-cddb-server") );
80     cddb_set_server_port(conn,
81                          config_GetInt( p_access,
82                                         MODULE_STRING "-cddb-port") );
83
84   /* Set the location of the local CDDB cache directory.
85      The default location of this directory is */
86
87     if (!config_GetInt( p_access, MODULE_STRING "-cddb-enable-cache" ))
88         cddb_cache_disable(conn);
89
90     cddb_cache_set_dir(conn,
91                      config_GetPsz( p_access,
92                                     MODULE_STRING "-cddb-cachedir") );
93
94     cddb_set_timeout(conn,
95                    config_GetInt( p_access, MODULE_STRING "-cddb-timeout") );
96
97
98     if (config_GetInt( p_access, MODULE_STRING "-cddb-httpd" ) )
99     {
100         cddb_http_enable(conn);
101     }
102     else
103     {
104         cddb_http_disable(conn);
105     }
106
107     p_cdda->cddb.disc = cddb_disc_new();
108
109     if (!p_cdda->cddb.disc)
110     {
111         msg_Err( p_access, "Unable to create CDDB disc structure." );
112         goto cddb_end;
113     }
114
115     for(i = 0; i < p_cdda->i_tracks; i++)
116     {
117         track_t i_track =  p_cdda->i_first_track + i;
118         cddb_track_t *t = cddb_track_new();
119         cddb_track_set_frame_offset(t, 
120                                     cdio_get_track_lba(p_cdio, i_track));
121         cddb_disc_add_track(p_cdda->cddb.disc, t);
122     }
123
124     cddb_disc_set_length(p_cdda->cddb.disc,
125                          cdio_get_track_lba(p_cdio, CDIO_CDROM_LEADOUT_TRACK)
126                          / CDIO_CD_FRAMES_PER_SEC);
127
128     if (!cddb_disc_calc_discid(p_cdda->cddb.disc))
129     {
130         msg_Err( p_access, "CDDB disc ID calculation failed" );
131         goto cddb_destroy;
132     }
133
134     i_matches = cddb_query(conn, p_cdda->cddb.disc);
135
136     if (i_matches > 0)
137     {
138         if (i_matches > 1)
139              msg_Warn( p_access, "Found %d matches in CDDB. Using first one.",
140                                  i_matches);
141         cddb_read(conn, p_cdda->cddb.disc);
142
143         if (p_cdda->i_debug & INPUT_DBG_CDDB)
144             cddb_disc_print(p_cdda->cddb.disc);
145
146     }
147     else
148     {
149         msg_Warn( p_access, "CDDB error: %s", cddb_error_str(errno));
150     }
151
152 cddb_destroy:
153     cddb_destroy(conn);
154
155 cddb_end: ;
156 }
157 #endif /*HAVE_LIBCDDB*/
158
159 #define add_meta_val(VLC_META, VAL)                           \
160   if ( p_cdda->p_meta && VAL) {                               \
161     /*vlc_meta_Add( p_cdda->p_meta, VLC_META, VAL );*/        \
162     dbg_print( INPUT_DBG_META, "field %s: %s\n",              \
163             input_MetaTypeToLocalizedString(VLC_META), VAL ); \
164   }                                                           \
165
166 #define add_cddb_meta(FIELD, VLC_META)                                  \
167   add_meta_val(VLC_META, cddb_disc_get_##FIELD(p_cdda->cddb.disc));
168
169 #define add_cddb_meta_fmt(FIELD, FORMAT_SPEC, VLC_META)                 \
170   {                                                                     \
171     char psz_buf[100];                                                  \
172     snprintf( psz_buf, sizeof(psz_buf)-1, FORMAT_SPEC,                  \
173               cddb_disc_get_##FIELD(p_cdda->cddb.disc));                               \
174     psz_buf[sizeof(psz_buf)-1] = '\0';                                  \
175     add_meta_val(VLC_META, psz_buf);                                    \
176   }
177
178 /* Adds a string-valued entry to the stream and media information if
179    the string is not null or the null string.
180  */
181 #define add_info_str(CATEGORY, TITLE, FIELD)                      \
182   if (FIELD && strlen(FIELD)) {                                   \
183     input_Control( p_cdda->p_input, INPUT_ADD_INFO, CATEGORY,     \
184                    _(TITLE), "%s", FIELD );                       \
185   }
186
187 /* Adds a numeric-valued entry to the stream and media information
188    if the number is not zero. */
189 #define add_info_val(CATEGORY, TITLE, FMT, FIELD)                 \
190   if (FIELD) {                                                    \
191     input_Control( p_cdda->p_input, INPUT_ADD_INFO, CATEGORY,     \
192                    _(TITLE), FMT, FIELD );                        \
193   }
194
195 /* Adds a CDDB string-valued entry to the stream and media information
196    under category "Disc" if the string is not null or the null string.
197  */
198 #define add_cddb_disc_info_str(TITLE, FIELD)                    \
199   add_info_str("Disc", TITLE, cddb_disc_get_##FIELD(p_cdda->cddb.disc))
200
201 /* Adds a CDDB numeric-valued entry to the stream and media information
202    under category "Disc" if the string is not null or the null string.
203  */
204 #define add_cddb_disc_info_val(TITLE, FMT, FIELD)               \
205   add_info_val("Disc", TITLE, FMT, cddb_disc_get_##FIELD(p_cdda->cddb.disc))
206
207 /* Adds a CD-Text string-valued entry to the stream and media information
208    under category "Disc" if the string is not null or the null string.
209  */
210 #define add_cdtext_info_str(CATEGORY, TITLE, INDEX, FIELD)              \
211     add_info_str(CATEGORY, TITLE, p_cdda->p_cdtext[INDEX]->field[FIELD])
212
213 /* Adds a CD-Text string-valued entry to the stream and media information
214    under category "Disc" if the string is not null or the null string.
215  */
216 #define add_cdtext_disc_info_str(TITLE, FIELD) \
217   add_cdtext_info_str("Disc", TITLE, 0, FIELD)
218
219
220 /*
221   Saves Meta Information about the CD-DA.
222
223   Meta information used in "stream and media info" or in playlist
224   info. The intialization of CD-Text or CDDB is done here though.
225   Therefore, this should be called before CDDAMetaInfo is called.
226
227  */
228 void 
229 CDDAMetaInfoInit( access_t *p_access )
230 {
231     cdda_data_t *p_cdda   = (cdda_data_t *) p_access->p_sys;
232     
233     if ( ! p_cdda ) return;
234
235     dbg_print( (INPUT_DBG_CALL), "p_cdda->i_tracks %d", 
236                p_cdda->i_tracks );
237
238     p_cdda->psz_mcn = cdio_get_mcn(p_cdda->p_cdio);
239 #if 0
240     p_cdda->p_meta = vlc_meta_New();
241 #endif
242
243 #ifdef HAVE_LIBCDDB
244     if ( p_cdda->b_cddb_enabled )
245     {
246         GetCDDBInfo(p_access, p_cdda);
247     }
248
249 #endif /*HAVE_LIBCDDB*/
250     
251 #define TITLE_MAX 30
252     {
253         track_t i_track;
254
255         for( i_track = 0 ; i_track < p_cdda->i_tracks ; i_track++ )
256         {
257             p_cdda->p_cdtext[i_track] =
258               cdio_get_cdtext(p_cdda->p_cdio, i_track);
259         }
260     }
261 }
262
263 /*
264  In the Control routine, we handle Meta Information requests and
265  basically copy what was saved in CDDAMetaInfoInit.
266
267  If i_track is CDIO_INVALID_TRACK we are probably asking about the entire
268  CD.
269  */
270 void 
271 CDDAMetaInfo( access_t *p_access, track_t i_track )
272 {
273     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
274     char *psz_meta_title = CDDAFormatMRL( p_access, i_track );
275     char *psz_meta_artist = NULL;
276     
277     if ( ! p_cdda ) return;
278
279     dbg_print( (INPUT_DBG_CALL), "i_track %d", i_track );
280
281 #ifdef HAVE_LIBCDDB
282
283     /* Set up for Meta and name for CDDB access. */
284     if ( p_cdda->b_cddb_enabled &&  p_cdda->cddb.disc )
285     {
286         if( CDIO_INVALID_TRACK == i_track )
287         {
288
289             psz_meta_title  = (char *)cddb_disc_get_title(p_cdda->cddb.disc);
290             psz_meta_artist = (char *)cddb_disc_get_artist(p_cdda->cddb.disc);
291             if ( cddb_disc_get_genre(p_cdda->cddb.disc) && 
292                      strlen(cddb_disc_get_genre(p_cdda->cddb.disc)) )
293                 add_cddb_meta(genre, vlc_meta_Genre);
294             if ( 0 != cddb_disc_get_year(p_cdda->cddb.disc))
295                 add_cddb_meta_fmt(year, "%d", vlc_meta_Date );
296         }
297         else
298         {
299           cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, i_track-1);
300           if (t != NULL )
301           {
302               if( cddb_track_get_title(t) != NULL && ! p_cdda->b_nav_mode )
303               {
304             add_meta_val( vlc_meta_Title, cddb_track_get_title(t) );
305               }
306               if( cddb_track_get_artist(t) != NULL )
307               {
308             add_meta_val( vlc_meta_Artist, cddb_track_get_artist(t) );
309               }
310           }
311         }
312     }
313
314 #endif /*HAVE_LIBCDDB*/
315     
316 #define TITLE_MAX 30
317     {
318         track_t i = p_cdda->i_tracks;
319         const int i_first_track = p_cdda->i_first_track;
320         char psz_buffer[MSTRTIME_MAX_SIZE];
321         unsigned int i_track_frames = 
322           cdio_get_track_lba(p_cdda->p_cdio, CDIO_CDROM_LEADOUT_TRACK);
323           
324         mtime_t i_duration = i_track_frames / CDIO_CD_FRAMES_PER_SEC;
325
326         dbg_print( INPUT_DBG_META, "Duration %ld, tracks %d", 
327                    (long int) i_duration, p_cdda->i_tracks );
328         input_Control( p_cdda->p_input, INPUT_ADD_INFO,
329                        _("Disc"), _("Duration"), "%s",
330                        secstotimestr( psz_buffer, i_duration ) );
331
332         if (p_cdda->psz_mcn) {
333             input_Control( p_cdda->p_input, INPUT_ADD_INFO,
334                            _("Disc"), _("Media Catalog Number (MCN)"), "%s", 
335                            p_cdda->psz_mcn );
336             
337             input_Control( p_cdda->p_input, INPUT_ADD_INFO,
338                            _("Disc"), _("Tracks"), "%d", p_cdda->i_tracks );
339         }
340         
341
342 #ifdef HAVE_LIBCDDB
343         if (p_cdda->b_cddb_enabled && p_cdda->cddb.disc)
344         {
345           add_cddb_disc_info_str("Artist (CDDB)", artist);
346           if ( CDDB_CAT_INVALID != cddb_disc_get_category(p_cdda->cddb.disc) )
347             add_info_str("Disc", "Category (CDDB)",
348                          CDDB_CATEGORY[cddb_disc_get_category(p_cdda->cddb.disc)]);
349           add_cddb_disc_info_val("Disc ID (CDDB)", "%x", discid);
350           add_cddb_disc_info_str("Extended Data (CDDB)", ext_data);
351           add_cddb_disc_info_str("Genre (CDDB)",  genre);
352           add_cddb_disc_info_str("Title (CDDB)",  title);
353           if ( 0 != cddb_disc_get_year(p_cdda->cddb.disc) ) 
354             add_cddb_disc_info_val("Year (CDDB)", "%d", year);
355
356         }
357 #endif /*HAVE_LIBCDDB*/
358
359         if (p_cdda->p_cdtext[0])
360         {
361             char *psz_field;
362           
363             add_cdtext_disc_info_str("Arranger (CD-Text)",    CDTEXT_ARRANGER);
364             add_cdtext_disc_info_str("Composer (CD-Text)",    CDTEXT_COMPOSER);
365             add_cdtext_disc_info_str("Disc ID (CD-Text)",     CDTEXT_DISCID);
366             add_cdtext_disc_info_str("Genre (CD-Text)",       CDTEXT_GENRE);
367             add_cdtext_disc_info_str("Message (CD-Text)",     CDTEXT_MESSAGE);
368             add_cdtext_disc_info_str("Performer (CD-Text)",   CDTEXT_PERFORMER);
369             add_cdtext_disc_info_str("Songwriter (CD-Text)",  CDTEXT_SONGWRITER);
370             add_cdtext_disc_info_str("Title (CD-Text)",       CDTEXT_TITLE);
371
372             psz_field = p_cdda->p_cdtext[0]->field[CDTEXT_TITLE];
373             if (psz_field && strlen(psz_field)) {   
374               psz_meta_title = psz_field;
375             }
376             psz_field = p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER];
377             if (psz_field && strlen(psz_field)) {   
378               psz_meta_artist = psz_field;
379             }
380             
381         }
382
383         for( i = 0 ; i < p_cdda->i_tracks ; i++ )
384         {
385           char psz_track[TITLE_MAX];
386           const track_t i_track = i_first_track + i;
387           unsigned int i_track_frames = 
388             cdio_get_track_lsn(p_cdda->p_cdio, i_track+1) - 
389             cdio_get_track_lsn(p_cdda->p_cdio, i_track);
390
391           mtime_t i_duration = i_track_frames / CDIO_CD_FRAMES_PER_SEC;
392           char *psz_mrl = CDDAFormatMRL( p_access, i_track );
393           
394           snprintf(psz_track, TITLE_MAX, "%s %02d", _("Track"), i_track);
395
396           input_Control( p_cdda->p_input, INPUT_ADD_INFO, psz_track,
397                          _("Duration"), "%s",
398                          secstotimestr( psz_buffer, i_duration ) );
399           
400           input_Control( p_cdda->p_input, INPUT_ADD_INFO, psz_track,
401                          _("MRL"), "%s", psz_mrl );
402           free(psz_mrl);
403           
404           if (p_cdda->p_cdtext[i_track])
405             {
406               add_cdtext_info_str( psz_track, "Arranger (CD-Text)",
407                                    i_track, CDTEXT_ARRANGER);
408               add_cdtext_info_str( psz_track, "Composer (CD-Text)",
409                                    i_track, CDTEXT_COMPOSER);
410               add_cdtext_info_str( psz_track, "Disc ID (CD-Text)",
411                                    i_track, CDTEXT_DISCID);
412               add_cdtext_info_str( psz_track, "Genre (CD-Text)",
413                                    i_track, CDTEXT_GENRE);
414               add_cdtext_info_str( psz_track, "Message (CD-Text)",
415                                    i_track, CDTEXT_MESSAGE);
416               add_cdtext_info_str( psz_track, "Performer (CD-Text)",
417                                    i_track, CDTEXT_PERFORMER);
418               add_cdtext_info_str( psz_track, "Songwriter (CD-Text)",
419                                    i_track, CDTEXT_SONGWRITER);
420               add_cdtext_info_str( psz_track, "Title (CD-Text)",
421                                    i_track, CDTEXT_TITLE);
422             }
423           
424 #ifdef HAVE_LIBCDDB
425           if (p_cdda->b_cddb_enabled)
426             {
427               cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, i);
428               if (t != NULL)
429                 {
430                   add_info_str(psz_track, "Artist (CDDB)", 
431                                cddb_track_get_artist(t));
432                   add_info_str(psz_track, "Title (CDDB)",  
433                                cddb_track_get_title(t));
434                   add_info_str(psz_track, "Extended Data (CDDB)",
435                                cddb_track_get_ext_data(t));
436                 }
437             }
438 #endif /*HAVE_LIBCDDB*/
439         }
440
441         /* Above we should have set psz_meta_title and psz_meta_artist
442            to CDDB or CD-Text values or the default value depending on
443            availablity and user preferences.
444
445            So now add the title and artist to VLC's meta, and the name
446            as shown in the status bar and playlist entry.
447
448            For playlist mode, the meta title is what's seen at the
449            bottom and in the playlist. For nav-mode playing, it is
450            done by input_control. I don't understand why they do
451            different things. In either case, we may have customized to
452            put in the track name.
453          */
454         if ( CDIO_INVALID_TRACK != i_track ) 
455         {
456             char *psz_name = CDDAFormatTitle( p_access, i_track ) ;
457             if ( !p_cdda->b_nav_mode ) {
458                 add_meta_val( vlc_meta_Title, psz_name );
459             } else 
460             { 
461                 input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_name );
462                 free(psz_name);
463             }
464             if (psz_meta_artist) 
465               add_meta_val( vlc_meta_Artist, psz_meta_artist );
466         }
467         
468     }
469 }
470
471 #define add_format_str_info(val)                         \
472   {                                                      \
473     const char *str = val;                               \
474     unsigned int len;                                    \
475     if (val != NULL) {                                   \
476       len=strlen(str);                                   \
477       if (len != 0) {                                    \
478         strncat(tp, str, TEMP_STR_LEN-(tp-temp_str));    \
479         tp += len;                                       \
480       }                                                  \
481       saw_control_prefix = false;                        \
482     }                                                    \
483   }
484
485 #define add_format_num_info(val, fmt)                    \
486   {                                                      \
487     char num_str[10];                                    \
488     unsigned int len;                                    \
489     sprintf(num_str, fmt, val);                          \
490     len=strlen(num_str);                                 \
491     if (len != 0) {                                      \
492       strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));  \
493       tp += len;                                         \
494     }                                                    \
495     saw_control_prefix = false;                          \
496   }
497
498 static inline bool
499 want_cddb_info(
500 cdda_data_t *p_cdda, char *psz_cdtext) 
501 {
502   /* We either don't have CD-Text info, or we do but we prefer to get CDDB
503      which means CDDB has been enabled and we were able to retrieve the info.*/
504 #ifdef HAVE_LIBCDDB
505   return !psz_cdtext || 
506     (!p_cdda->b_cdtext_prefer && p_cdda->b_cddb_enabled && p_cdda->cddb.disc);
507 #else
508   return false;
509 #endif
510 }
511
512
513 /*!
514    Take a format string and expand escape sequences, that is sequences that
515    begin with %, with information from the current CD.
516    The expanded string is returned. Here is a list of escape sequences:
517
518    %a : The album artist **
519    %A : The album information **
520    %C : Category **
521    %e : The extended track data
522    %I : CDDB disk ID **
523    %G : Genre **
524    %M : The current MRL
525    %m : The CD-DA Media Catalog Number (MCN)
526    %n : The number of tracks on the CD
527    %p : The artist/performer/composer in the track **
528    %T : The track number **
529    %s : Number of seconds in this track, or seconds in CD if invalid track
530    %S : Number of seconds on the CD
531    %t : The track name or MRL if no name 
532    %Y : The year 19xx or 20xx **
533    %% : a %
534 */
535 char *
536 CDDAFormatStr( const access_t *p_access, cdda_data_t *p_cdda,
537                const char format_str[], const char *psz_mrl, track_t i_track)
538 {
539 #define TEMP_STR_SIZE 256
540 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
541     static char temp_str[TEMP_STR_SIZE];
542     size_t i;
543     char * tp = temp_str;
544     vlc_bool_t saw_control_prefix = false;
545     size_t format_len = strlen(format_str);
546
547     memset(temp_str, 0, TEMP_STR_SIZE);
548
549     for (i=0; i<format_len; i++)
550     {
551         char *psz = NULL;
552
553         if (!saw_control_prefix && format_str[i] != '%')
554         {
555             *tp++ = format_str[i];
556             saw_control_prefix = false;
557             continue;
558         }
559
560         switch(format_str[i])
561         {
562             case '%':
563               if (saw_control_prefix)
564               {
565                   *tp++ = '%';
566               }
567               saw_control_prefix = !saw_control_prefix;
568               break;
569 #ifdef HAVE_LIBCDDB
570             case 'a':
571                 if (p_cdda->p_cdtext[0]
572                     && p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER])
573                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER];
574                 if (want_cddb_info(p_cdda, psz))
575                   psz = (char *)cddb_disc_get_artist(p_cdda->cddb.disc);
576                 goto format_str;
577             case 'A':
578                 if (p_cdda->p_cdtext[0]
579                     && p_cdda->p_cdtext[0]->field[CDTEXT_TITLE])
580                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_TITLE];
581                 if (want_cddb_info(p_cdda, psz))
582                   psz =  (char *)cddb_disc_get_title(p_cdda->cddb.disc);
583                 goto format_str;
584             case 'C':
585                 if (!p_cdda->b_cddb_enabled) goto not_special;
586                 if (p_cdda->cddb.disc)
587                     add_format_str_info(CDDB_CATEGORY[cddb_disc_get_category(p_cdda->cddb.disc)]);
588                 break;
589             case 'G':
590                 if (p_cdda->p_cdtext[0]
591                     && p_cdda->p_cdtext[0]->field[CDTEXT_GENRE])
592                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_GENRE];
593                 if (want_cddb_info(p_cdda, psz))
594                   psz = (char *)cddb_disc_get_genre(p_cdda->cddb.disc);
595                 goto format_str;
596             case 'I':
597                 if (p_cdda->p_cdtext[0]
598                     && p_cdda->p_cdtext[0]->field[CDTEXT_DISCID])
599                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_DISCID];
600                 if (want_cddb_info(p_cdda, psz)) {
601                      add_format_num_info(cddb_disc_get_discid(p_cdda->cddb.disc), "%x");
602                 } else if (psz)
603                      add_format_str_info(psz);
604                 break;
605             case 'Y':
606                 if (!p_cdda->b_cddb_enabled) goto not_special;
607                 if (p_cdda->cddb.disc)
608                     add_format_num_info(cddb_disc_get_year(p_cdda->cddb.disc), 
609                                         "%5d");
610                 break;
611             case 't':
612                 if ( CDIO_INVALID_TRACK == i_track ) break;
613                 if (p_cdda && p_cdda->b_cddb_enabled && p_cdda->cddb.disc)
614                 {
615                     cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
616                                                         i_track-1);
617                     if (t != NULL && cddb_track_get_title(t) != NULL) {
618                       add_format_str_info(cddb_track_get_title(t));
619                     } else {
620                       add_format_str_info(psz_mrl);
621                     }
622                 } else {
623                   if (p_cdda->p_cdtext[i_track]
624                       && p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE]) {
625                     add_format_str_info(p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE]);
626                   
627                   } else 
628                     add_format_str_info(psz_mrl);
629                 }
630                 break;
631             case 'p':
632                 if ( CDIO_INVALID_TRACK == i_track ) break;
633                 if (p_cdda->p_cdtext[i_track] 
634                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER])
635                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER];
636                 if (want_cddb_info(p_cdda, psz))
637                   {
638                     cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
639                                                         i_track-1);
640                     if (t != NULL && cddb_track_get_artist(t) != NULL)
641                       psz = (char *)cddb_track_get_artist(t);
642                   }
643                 goto format_str;
644             case 'e':
645                 if ( CDIO_INVALID_TRACK == i_track ) break;
646                 if (p_cdda->p_cdtext[i_track] 
647                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE])
648                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE];
649                 if (want_cddb_info(p_cdda, psz))
650                 {
651                     cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
652                                                         i_track-1);
653                     if (t != NULL && cddb_track_get_ext_data(t) != NULL)
654                         psz = (char *)cddb_track_get_ext_data(t);
655                 } 
656                 goto format_str;
657                 break;
658 #else
659             case 'a':
660                 if (p_cdda->p_cdtext[0] 
661                     && p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER])
662                     psz = p_cdda->p_cdtext[0]->field[CDTEXT_PERFORMER];
663                 goto format_str;
664             case 'A':
665                 if (p_cdda->p_cdtext[0] 
666                     && p_cdda->p_cdtext[0]->field[CDTEXT_TITLE])
667                     psz = p_cdda->p_cdtext[0]->field[CDTEXT_TITLE];
668                 goto format_str;
669             case 'G':
670                 if (p_cdda->p_cdtext[0] 
671                     && p_cdda->p_cdtext[0]->field[CDTEXT_GENRE])
672                   psz = p_cdda->p_cdtext[0]->field[CDTEXT_GENRE];
673                 goto format_str;
674             case 'I':
675                 if (p_cdda->p_cdtext[0] 
676                     && p_cdda->p_cdtext[0]->field[CDTEXT_DISCID])
677                   add_format_str_info(p_cdda->p_cdtext[0]->field[CDTEXT_DISCID]);
678                 break;
679             case 'p':
680                 if ( CDIO_INVALID_TRACK == i_track ) break;
681                 if (p_cdda->p_cdtext[i_track] 
682                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER])
683                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_PERFORMER];
684                 goto format_str;
685             case 't':
686                 if ( CDIO_INVALID_TRACK == i_track ) break;
687                 if (p_cdda->p_cdtext[i_track] 
688                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE])
689                     psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_TITLE];
690                 else 
691                     psz = psz_mrl;
692                 goto format_str;
693             case 'e':
694                 if ( CDIO_INVALID_TRACK == i_track ) break;
695                 if (p_cdda->p_cdtext[i_track] 
696                     && p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE])
697                   psz = p_cdda->p_cdtext[i_track]->field[CDTEXT_MESSAGE];
698                 goto format_str;
699                 break;
700 #endif /*HAVE_LIBCDDB*/
701
702             case 's':
703                 if ( CDIO_INVALID_TRACK != i_track )
704                 {
705                     char psz_buffer[MSTRTIME_MAX_SIZE];
706                     unsigned int i_track_frames = 
707                       cdio_get_track_sec_count(p_cdda->p_cdio, i_track);
708                     mtime_t i_duration = 
709                       i_track_frames / CDIO_CD_FRAMES_PER_SEC;
710                     add_format_str_info( secstotimestr( psz_buffer, 
711                                                         i_duration ) );
712                     break;
713                 }
714
715                 /* Fall through to disc duration if CDIO_INVALID_TRACK  */
716             case 'S':
717                 {
718                     char psz_buffer[MSTRTIME_MAX_SIZE];
719                     unsigned int i_track_frames = 
720                       cdio_get_track_lba(p_cdda->p_cdio, 
721                                          CDIO_CDROM_LEADOUT_TRACK);
722                     mtime_t i_duration = 
723                       i_track_frames / CDIO_CD_FRAMES_PER_SEC;
724                     add_format_str_info( secstotimestr( psz_buffer, 
725                                                         i_duration ) );
726                     break;
727                 }
728
729             case 'M':
730               add_format_str_info(psz_mrl);
731               break;
732
733             case 'm':
734               add_format_str_info(p_cdda->psz_mcn);
735               break;
736
737             case 'n':
738               add_format_num_info(p_cdda->i_tracks, "%d");
739               break;
740
741             case 'T':
742               add_format_num_info(i_track, "%02d");
743               break;
744             format_str:
745               if (psz)
746                 add_format_str_info(psz);
747               break;
748 #ifdef HAVE_LIBCDDB
749             not_special:
750 #endif
751             default:
752                 *tp++ = '%';
753                 *tp++ = format_str[i];
754                 saw_control_prefix = false;
755         }
756     }
757     return strdup(temp_str);
758 }
759
760 /* Return a MRL for the given track. The caller must free the 
761    allocated string. */
762 static char *
763 CDDAFormatMRL( const access_t *p_access, track_t i_track )
764 {
765     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
766     const unsigned int psz_mrl_max = strlen(CDDA_MRL_PREFIX) 
767       + strlen(p_cdda->psz_source) +
768       + strlen("@T") + strlen("100") + 1;
769     char *psz_mrl = calloc( 1, psz_mrl_max );
770     
771     if (CDIO_INVALID_TRACK == i_track)
772       snprintf(psz_mrl, psz_mrl_max, "%s%s",
773                CDDA_MRL_PREFIX, p_cdda->psz_source);
774     else 
775       snprintf(psz_mrl, psz_mrl_max, "%s%s@T%u",
776                CDDA_MRL_PREFIX, p_cdda->psz_source, i_track);
777     return psz_mrl;
778 }
779
780
781 /* Return a title string as specified by the titel format string for the 
782    given track. The caller must free the allocated string. */
783 char *
784 CDDAFormatTitle( const access_t *p_access, track_t i_track )
785
786
787     const char *config_varname = MODULE_STRING "-title-format";
788     cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
789     char *psz_mrl = CDDAFormatMRL( p_access, i_track );
790
791     if( psz_mrl ) 
792     {
793         char *psz_name;
794 #ifdef HAVE_LIBCDDB
795         if (p_cdda->b_cddb_enabled)
796         {
797             config_varname = MODULE_STRING "-cddb-title-format";
798         }
799 #endif /*HAVE_LIBCDDB*/
800         psz_name = 
801           CDDAFormatStr( p_access, p_cdda,
802                          config_GetPsz( p_access, config_varname ),
803                          psz_mrl, i_track );
804         free(psz_mrl);
805         return psz_name;
806     }
807     return(NULL);
808 }
809
810 /* Adds a string-valued entry to the playlist information under "Track"
811    if the string is not null or the null string.
812  */
813 #define add_playlist_track_info_str(TITLE, FIELD)                        \
814     if (FIELD && strlen(FIELD))                                          \
815     {                                                                    \
816         input_ItemAddInfo( &p_item->input, _("Track"), _(TITLE),    \
817                               "%s", FIELD);                              \
818     }
819
820 static playlist_item_t *
821 CDDACreatePlaylistItem( const access_t *p_access, cdda_data_t *p_cdda,
822                         playlist_t *p_playlist, playlist_item_t *p_item, 
823                         track_t i_track )
824 {
825     unsigned int i_track_frames = 
826         cdio_get_track_lsn(p_cdda->p_cdio, i_track+1) - 
827         cdio_get_track_lsn(p_cdda->p_cdio, i_track);
828     mtime_t i_mduration = i_track_frames * (CLOCK_FREQ / CDIO_CD_FRAMES_PER_SEC) ;
829     char *psz_title = NULL;
830     char *psz_mrl   = NULL;
831
832     playlist_item_t *p_child = NULL;
833
834     if( !p_item ) return NULL;
835
836     psz_title = CDDAFormatTitle( p_access, i_track ) ;
837     psz_mrl = CDDAFormatMRL( p_access, i_track  ) ;
838
839     dbg_print( INPUT_DBG_META, "mrl: %s, title: %s, duration, %ld",
840                psz_mrl, psz_title, (long int) i_mduration / 1000000 );
841
842     p_child = playlist_ItemNew( p_playlist, psz_mrl, psz_title );
843     input_GetItem(p_child->p_input)->i_duration = (mtime_t) i_mduration;
844     free(psz_mrl);
845     free(psz_title);
846
847     if( !p_child ) return NULL;
848     return p_child;
849 }
850
851 int CDDAAddMetaToItem( access_t *p_access, cdda_data_t *p_cdda,
852                        playlist_item_t *p_item, int i_track,
853                        vlc_bool_t b_single )
854 {
855 #if 0
856     add_playlist_track_info_str("Source",  p_cdda->psz_source);
857     input_ItemAddInfo( &p_item->input, _("Track"), _("Track Number"),
858                            "%d", i_track );
859
860     if (p_cdda->p_cdtext[i_track])
861     {
862         const cdtext_t *p = p_cdda->p_cdtext[i_track];
863         add_playlist_track_info_str("Arranger (CD-Text)",
864                                     p->field[CDTEXT_ARRANGER]);
865         add_playlist_track_info_str("Composer (CD-Text)",
866                                     p->field[CDTEXT_COMPOSER]);
867         add_playlist_track_info_str("Genre (CD-Text)",
868                                     p->field[CDTEXT_GENRE]);
869         add_playlist_track_info_str("Message (CD-Text)",
870                                     p->field[CDTEXT_MESSAGE]);
871         add_playlist_track_info_str("Performer (CD-Text)",
872                                     p->field[CDTEXT_PERFORMER]);
873         add_playlist_track_info_str("Songwriter (CD-Text)",
874                                     p->field[CDTEXT_SONGWRITER]);
875         add_playlist_track_info_str("Title (CD-Text)",
876                                     p->field[CDTEXT_TITLE]);
877     }
878
879 #ifdef HAVE_LIBCDDB
880     if (p_cdda->b_cddb_enabled)
881     {
882         cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
883                                             i_track-p_cdda->i_first_track);
884
885         if (t)
886         {
887             if (cddb_track_get_artist(t))
888                 add_playlist_track_info_str("Artist (CDDB)",
889                                              cddb_track_get_artist(t));
890             if (cddb_track_get_title(t))
891                 add_playlist_track_info_str("Title (CDDB)",
892                                             cddb_track_get_title(t));
893             if (cddb_track_get_ext_data(t))
894                 add_playlist_track_info_str("Extended information (CDDB)",
895                                             cddb_track_get_ext_data(t));
896         }
897     }
898 #endif /*HAVE_LIBCDDB*/
899 #endif
900     return VLC_SUCCESS;
901 }
902
903 /* 
904    Fixes up playlist. 
905 */
906 int
907 CDDAFixupPlaylist( access_t *p_access, cdda_data_t *p_cdda, 
908                    vlc_bool_t b_single_track )
909 {
910     int i;
911     playlist_t * p_playlist = NULL;
912     const track_t i_first_track = p_cdda->i_first_track;
913     playlist_item_t *p_item = NULL;
914     vlc_bool_t b_play = VLC_FALSE;
915     track_t    i_track;
916
917 #ifdef HAVE_LIBCDDB
918     p_cdda->b_cddb_enabled =
919         config_GetInt( p_access, MODULE_STRING "-cddb-enabled" );
920     if( b_single_track && !p_cdda->b_cddb_enabled )
921         return VLC_SUCCESS;
922 #else
923     if( b_single_track )
924         return VLC_SUCCESS;
925 #endif
926
927     if (! p_cdda->b_nav_mode ) {
928         p_playlist = pl_Yield( p_access );
929     }
930
931     if( b_single_track || p_cdda->b_nav_mode ) {
932         i_track = p_cdda->i_track;
933     }
934     else
935     {
936         i_track = CDIO_INVALID_TRACK;
937     }
938     CDDAMetaInfoInit( p_access );
939     CDDAMetaInfo( p_access, p_cdda->i_track );
940
941     if( p_playlist )
942     {
943         input_thread_t *p_input = (input_thread_t*)vlc_object_find( p_access, VLC_OBJECT_INPUT, FIND_PARENT );
944         if( p_input )
945         {
946             p_item = playlist_ItemGetByInput( p_playlist, input_GetItem(p_input), VLC_FALSE );
947
948             if( p_item == p_playlist->status.p_item && !b_single_track )
949                 b_play = VLC_TRUE;
950             else
951                 b_play = VLC_FALSE;
952             vlc_object_release( p_input );
953         }
954     }
955
956     if( b_single_track && !p_cdda->b_nav_mode )
957     {
958         /*May fill out more information when the playlist user interface becomes
959            more mature.
960          */
961         track_t i_track = p_cdda->i_track;
962         unsigned int i_track_frames = 
963           cdio_get_track_sec_count(p_cdda->p_cdio, i_track);
964         
965         input_title_t *t = p_cdda->p_title[0] = //i_track-i_first_track] =
966         vlc_input_title_New();
967
968         asprintf( &t->psz_name, _("Track %i"), i_track );
969         t->i_size = i_track_frames * (int64_t) CDIO_CD_FRAMESIZE_RAW;
970
971         t->i_length = I64C(1000000) * t->i_size / CDDA_FREQUENCY_SAMPLE / 4;
972
973         if( p_item ) 
974         {
975             CDDAAddMetaToItem( p_access, p_cdda, p_item, i_track, VLC_FALSE );
976             p_item->p_input->i_duration = (mtime_t) i_track_frames 
977               * (CLOCK_FREQ / CDIO_CD_FRAMES_PER_SEC);
978             p_item->p_input->psz_uri = CDDAFormatMRL( p_access, i_track );
979         }
980         
981         p_cdda->i_titles = 1;
982         p_access->info.i_update = INPUT_UPDATE_TITLE;
983     }
984     else
985     {
986         input_title_t *t;
987
988         if ( !p_cdda->b_nav_mode )
989           playlist_ItemToNode( p_playlist, p_item, VLC_FALSE );
990
991         for( i = 0 ; i < p_cdda->i_tracks ; i++ )
992         {
993             playlist_item_t *p_child;
994             const track_t i_track = i_first_track + i;
995             unsigned int i_track_frames = 
996               cdio_get_track_sec_count(p_cdda->p_cdio, i_track);
997
998             t = p_cdda->p_title[i] = vlc_input_title_New();
999
1000             asprintf( &t->psz_name, _("Track %i"), i_track );
1001             t->i_size = i_track_frames * (int64_t) CDIO_CD_FRAMESIZE_RAW;
1002
1003             t->i_length = I64C(1000000) * t->i_size 
1004               / CDDA_FREQUENCY_SAMPLE / 4;
1005
1006             if ( ! p_cdda->b_nav_mode ) {
1007               p_child = CDDACreatePlaylistItem( p_access, p_cdda, p_playlist,
1008                                                 p_item,
1009                                                 i_track );
1010               CDDAAddMetaToItem( p_access, p_cdda, p_child, i_track, 
1011                                  VLC_TRUE );
1012             }
1013         }
1014
1015         p_cdda->i_titles = p_cdda->i_tracks;
1016         p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE;
1017         if( p_item )
1018         {
1019             p_item->p_input->i_duration = (mtime_t)
1020               p_access->info.i_size * (CLOCK_FREQ / CDIO_CD_FRAMES_PER_SEC) ;
1021             p_item->p_input->psz_uri    = CDDAFormatMRL( p_access, p_cdda->i_track );
1022         }
1023     }
1024     
1025
1026     if( b_play )
1027     {
1028         playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VLC_TRUE,
1029                           p_playlist->status.p_item, NULL );
1030     }
1031
1032     if (p_playlist) vlc_object_release( p_playlist );
1033     return VLC_SUCCESS;
1034 }
1035
1036
1037 /* 
1038  * Local variables:
1039  *  mode: C
1040  *  style: gnu
1041  * End:
1042  */