]> git.sesse.net Git - vlc/blob - modules/access/cdda/info.c
First attempt at adding CD-Text.
[vlc] / modules / access / cdda / info.c
1 /*****************************************************************************
2  * info.c : CD digital audio input information routines
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id: info.c 8845 2004-09-29 09:00:41Z rocky $
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., 59 Temple Place - Suite 330, Boston, MA  02111, 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 #define CDDA_MRL_PREFIX "cddax://"
42
43 #ifdef HAVE_LIBCDDB
44
45 #define free_and_dup(var, val) \
46   if (var) free(var);          \
47   if (val) var=strdup(val);
48
49
50 static void
51 GetCDDBInfo( access_t *p_access, cdda_data_t *p_cdda )
52 {
53
54   int i, i_matches;
55   cddb_conn_t  *conn = cddb_new();
56   const CdIo *p_cdio = p_cdda->p_cdio;
57
58   dbg_print( (INPUT_DBG_CALL), "" );
59
60 #ifdef FIXME_NOW
61   cddb_log_set_handler (uninit_log_handler);
62 #endif
63   
64   if (!conn) {
65     msg_Warn( p_access, "Unable to initialize libcddb" );
66     goto cddb_destroy;
67   }
68   
69   cddb_set_email_address( conn,
70                           config_GetPsz( p_access,
71                                          MODULE_STRING "-cddb-email") );
72   
73   cddb_set_server_name( conn,
74                         config_GetPsz( p_access,
75                                        MODULE_STRING "-cddb-server") );
76   
77   cddb_set_server_port(conn,
78                        config_GetInt( p_access,
79                                       MODULE_STRING "-cddb-port") );
80   
81   /* Set the location of the local CDDB cache directory.
82      The default location of this directory is */
83   
84   if (!config_GetInt( p_access, MODULE_STRING "-cddb-enable-cache" ))
85     cddb_cache_disable(conn);
86   
87   cddb_cache_set_dir(conn,
88                      config_GetPsz( p_access,
89                                     MODULE_STRING "-cddb-cachedir") );
90   
91   cddb_set_timeout(conn,
92                    config_GetInt( p_access, MODULE_STRING "-cddb-timeout") );
93   
94   
95   if (config_GetInt( p_access, MODULE_STRING "-cddb-httpd" )) {
96     cddb_http_enable(conn);
97   } else
98     cddb_http_disable(conn);
99   
100   p_cdda->cddb.disc = cddb_disc_new();
101   if (!p_cdda->cddb.disc) {
102     msg_Err( p_access, "Unable to create CDDB disc structure." );
103     goto cddb_end;
104   }
105   
106   for(i = 0; i < p_cdda->i_tracks; i++) {
107     track_t i_track =  p_cdda->i_first_track + i;
108     cddb_track_t *t = cddb_track_new();
109     t->frame_offset = cdio_get_track_lba(p_cdio, i_track);
110     cddb_disc_add_track(p_cdda->cddb.disc, t);
111   }
112   
113   p_cdda->cddb.disc->length =
114     cdio_get_track_lba(p_cdio, CDIO_CDROM_LEADOUT_TRACK)
115     / CDIO_CD_FRAMES_PER_SEC;
116   
117   if (!cddb_disc_calc_discid(p_cdda->cddb.disc)) {
118     msg_Err( p_access, "CDDB disc ID calculation failed" );
119     goto cddb_destroy;
120   }
121   
122   i_matches = cddb_query(conn, p_cdda->cddb.disc);
123   if (i_matches > 0) {
124     if (i_matches > 1)
125       msg_Warn( p_access, "Found %d matches in CDDB. Using first one.",
126                 i_matches);
127     cddb_read(conn, p_cdda->cddb.disc);
128     
129     if (p_cdda->i_debug & INPUT_DBG_CDDB)
130       cddb_disc_print(p_cdda->cddb.disc);
131     
132   } else {
133     msg_Warn( p_access, "CDDB error: %s", cddb_error_str(errno));
134   }
135
136  cddb_destroy:
137   cddb_destroy(conn);
138
139  cddb_end: ;
140 }
141 #endif /*HAVE_LIBCDDB*/
142
143 #define add_meta_val(FIELD, VLC_META, VAL)                              \
144   if ( p_cdda->p_meta && VAL) {                                         \
145     vlc_meta_Add( p_cdda->p_meta, VLC_META, VAL );                      \
146     dbg_print( INPUT_DBG_META, "field %s: %s\n", VLC_META, VAL );       \
147   }                                                                     \
148     
149 #define add_cddb_meta(FIELD, VLC_META)                                  \
150   add_meta_val(FIELD, VLC_META, p_cdda->cddb.disc->FIELD);
151     
152 #define add_cddb_meta_fmt(FIELD, FORMAT_SPEC, VLC_META)                 \
153   {                                                                     \
154     char psz_buf[100];                                                  \
155     snprintf( psz_buf, sizeof(psz_buf)-1, FORMAT_SPEC,                  \
156               p_cdda->cddb.disc->FIELD );                               \
157     psz_buf[sizeof(psz_buf)-1] = '\0';                                  \
158     add_meta_val(FIELD, VLC_META, psz_buf);                             \
159   }    
160
161 /* Adds a string-valued entry to the stream and media information if
162    the string is not null or the null string.
163  */
164 #define add_info_str(CATEGORY, TITLE, FIELD)                      \
165   if (FIELD && strlen(FIELD)) {                                   \
166     input_Control( p_cdda->p_input, INPUT_ADD_INFO, CATEGORY,     \
167                    _(TITLE), "%s", FIELD );                       \
168   }  
169   
170 /* Adds a numeric-valued entry to the stream and media information 
171    if the number is not zero. */
172 #define add_info_val(CATEGORY, TITLE, FMT, FIELD)                 \
173   if (FIELD) {                                                    \
174     input_Control( p_cdda->p_input, INPUT_ADD_INFO, CATEGORY,     \
175                    _(TITLE), FMT, FIELD );                        \
176   }  
177
178 /* Adds a CDDB string-valued entry to the stream and media information
179    under category "Disc" if the string is not null or the null string.
180  */
181 #define add_cddb_disc_info_str(TITLE, FIELD)                    \
182   add_info_str("Disc", TITLE, p_cdda->cddb.disc->FIELD)
183
184 /* Adds a CDDB numeric-valued entry to the stream and media information
185    under category "Disc" if the string is not null or the null string.
186  */
187 #define add_cddb_disc_info_val(TITLE, FMT, FIELD)               \
188   add_info_val("Disc", TITLE, FMT, p_cdda->cddb.disc->FIELD)
189
190 /* Adds a CD-Text string-valued entry to the stream and media information
191    under category "Disc" if the string is not null or the null string.
192  */
193 #define add_cdtext_info_str(CATEGORY, TITLE, INDEX, FIELD)              \
194     add_info_str(CATEGORY, TITLE, p_cdda->p_cdtext[INDEX]->field[FIELD])
195
196 /* Adds a CD-Text string-valued entry to the stream and media information
197    under category "Disc" if the string is not null or the null string.
198  */
199 #define add_cdtext_disc_info_str(TITLE, FIELD)  \
200   add_cdtext_info_str("Disc", TITLE, 0, FIELD)
201
202
203 /*
204  Gets and saves CDDA Meta Information about the CD.
205
206  In the Control routine, we handle Meta Information requests and
207  basically copy what we've saved here.
208
209  Meta information is also used elsewhere such as in "stream and
210  media info" or in playlist info. The intialization of CD-Text or CDDB
211  is done here though.
212  */    
213 void 
214 CDDAMetaInfo( access_t *p_access  )
215 {
216   cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys;
217
218   if ( ! p_cdda ) return;
219
220   p_cdda->psz_mcn = cdio_get_mcn(p_cdda->p_cdio);
221   
222 #ifdef HAVE_LIBCDDB
223   if ( p_cdda->b_cddb_enabled ) {
224     
225     GetCDDBInfo(p_access, p_cdda);
226     
227     if ( p_cdda->cddb.disc ) {
228       
229       p_cdda->p_meta = vlc_meta_New();
230       
231       add_cddb_meta(title,    VLC_META_CDDB_TITLE);
232       add_cddb_meta(artist,   VLC_META_CDDB_ARTIST);
233       add_cddb_meta(genre,    VLC_META_CDDB_GENRE);
234       add_cddb_meta(ext_data, VLC_META_CDDB_EXT_DATA);
235       
236       add_cddb_meta_fmt(year,   "%d", VLC_META_CDDB_YEAR);
237       add_cddb_meta_fmt(discid, "%x", VLC_META_CDDB_DISCID);
238     }
239   }
240
241 #endif /*HAVE_LIBCDDB*/
242 #define TITLE_MAX 30
243   
244   {
245     track_t i = p_cdda->i_tracks;
246     const int i_first_track = p_cdda->i_first_track;
247     char psz_buffer[MSTRTIME_MAX_SIZE];
248     mtime_t i_duration =
249       (p_cdda->lsn[i_first_track+i] - p_cdda->lsn[i_first_track])
250       / CDIO_CD_FRAMES_PER_SEC;
251     
252     dbg_print( INPUT_DBG_META, "Duration %ld", (long int) i_duration );
253     input_Control( p_cdda->p_input, INPUT_ADD_INFO, 
254                    _("Disc"), _("Duration"), "%s",
255                    secstotimestr( psz_buffer, i_duration ) );
256     
257 #ifdef HAVE_LIBCDDB
258     if (p_cdda->b_cddb_enabled && p_cdda->cddb.disc) {
259       add_cddb_disc_info_str("Artist (CDDB)", artist);
260       add_cddb_disc_info_str("Genre (CDDB)",  genre);
261       add_cddb_disc_info_str("Extended Data (CDDB)", ext_data);
262       add_cddb_disc_info_val("Year (CDDB)", "%d", year);
263       add_cddb_disc_info_val("Disc ID (CDDB)", "%x", discid);
264       add_cddb_disc_info_str("Title (CDDB)",  title);
265       add_info_str("Disc", "Category (CDDB)",  
266                    CDDB_CATEGORY[p_cdda->cddb.disc->category]);
267     }
268 #endif /*HAVE_LIBCDDB*/
269
270     p_cdda->p_cdtext[0] = cdio_get_cdtext(p_cdda->p_cdio, 0);
271     if (p_cdda->p_cdtext[0]) {
272       add_cdtext_disc_info_str("Arranger (CD-Text)",    CDTEXT_ARRANGER);
273       add_cdtext_disc_info_str("Composer (CD-Text)",    CDTEXT_COMPOSER);
274       add_cdtext_disc_info_str("Disc ID (CD-Text)",     CDTEXT_DISCID);
275       add_cdtext_disc_info_str("Genre (CD-Text)",       CDTEXT_GENRE);
276       add_cdtext_disc_info_str("Message (CD-Text)",     CDTEXT_MESSAGE);
277       add_cdtext_disc_info_str("Performer (CD-Text)",   CDTEXT_PERFORMER);
278       add_cdtext_disc_info_str("Songwriter (CD-Text)",  CDTEXT_SONGWRITER);
279       add_cdtext_disc_info_str("Title (CD-Text)",       CDTEXT_TITLE);
280     }
281     
282     for( i = 0 ; i < p_cdda->i_tracks ; i++ ) {
283
284       char psz_track[TITLE_MAX];
285       const track_t i_track = i_first_track + i;
286       mtime_t i_duration = (p_cdda->lsn[i_track+1] - p_cdda->lsn[i_track]) 
287         / CDIO_CD_FRAMES_PER_SEC;
288       snprintf(psz_track, TITLE_MAX, "%s %02d", _("Track"), i_track);
289       input_Control( p_cdda->p_input, INPUT_ADD_INFO, psz_track, 
290                      _("Duration"), "%s", 
291                      secstotimestr( psz_buffer, i_duration ) );
292
293       p_cdda->p_cdtext[i_track] = cdio_get_cdtext(p_cdda->p_cdio, i_track);
294       
295       if (p_cdda->p_cdtext[i_track]) {
296         add_cdtext_info_str(psz_track, "Arranger (CD-Text)",    i_track, 
297                             CDTEXT_ARRANGER);
298         add_cdtext_info_str(psz_track, "Composer (CD-Text)",    i_track, 
299                             CDTEXT_COMPOSER);
300         add_cdtext_info_str(psz_track, "Disc ID (CD-Text)",     i_track, 
301                             CDTEXT_DISCID);
302         add_cdtext_info_str(psz_track, "Genre (CD-Text)",       i_track, 
303                             CDTEXT_GENRE);
304         add_cdtext_info_str(psz_track, "Message (CD-Text)",     i_track, 
305                             CDTEXT_MESSAGE);
306         add_cdtext_info_str(psz_track, "Performer (CD-Text)",   i_track, 
307                             CDTEXT_PERFORMER);
308         add_cdtext_info_str(psz_track, "Songwriter (CD-Text)",  i_track, 
309                             CDTEXT_SONGWRITER);
310         add_cdtext_info_str(psz_track, "Title (CD-Text)",       i_track, 
311                             CDTEXT_TITLE);
312       }
313
314 #ifdef HAVE_LIBCDDB
315       if (p_cdda->b_cddb_enabled) {
316         cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, i);
317         if (t != NULL) {
318           add_info_str(psz_track, "Artist (CDDB)", t->artist);
319           add_info_str(psz_track, "Title (CDDB)",  t->title);
320           add_info_str(psz_track, "Extended Data (CDDB)", t->ext_data);
321         }
322       }
323 #endif /*HAVE_LIBCDDB*/
324     }
325   }
326 }
327
328 #define add_format_str_info(val)                         \
329   {                                                      \
330     const char *str = val;                               \
331     unsigned int len;                                    \
332     if (val != NULL) {                                   \
333       len=strlen(str);                                   \
334       if (len != 0) {                                    \
335         strncat(tp, str, TEMP_STR_LEN-(tp-temp_str));    \
336         tp += len;                                       \
337       }                                                  \
338       saw_control_prefix = false;                        \
339     }                                                    \
340   }
341
342 #define add_format_num_info(val, fmt)                    \
343   {                                                      \
344     char num_str[10];                                    \
345     unsigned int len;                                    \
346     sprintf(num_str, fmt, val);                          \
347     len=strlen(num_str);                                 \
348     if (len != 0) {                                      \
349       strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));  \
350       tp += len;                                         \
351     }                                                    \
352     saw_control_prefix = false;                          \
353   }
354
355 /*!
356    Take a format string and expand escape sequences, that is sequences that
357    begin with %, with information from the current CD.
358    The expanded string is returned. Here is a list of escape sequences:
359
360    %a : The album artist **
361    %A : The album information **
362    %C : Category **
363    %I : CDDB disk ID **
364    %G : Genre **
365    %M : The current MRL
366    %m : The CD-DA Media Catalog Number (MCN)
367    %n : The number of tracks on the CD
368    %p : The artist/performer/composer in the track **
369    %T : The track number **
370    %s : Number of seconds in this track
371    %t : The name **
372    %Y : The year 19xx or 20xx **
373    %% : a %
374 */
375 static char *
376 CDDAFormatStr( const access_t *p_access, cdda_data_t *p_cdda,
377                const char format_str[], const char *mrl, track_t i_track)
378 {
379 #define TEMP_STR_SIZE 256
380 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
381   static char    temp_str[TEMP_STR_SIZE];
382   size_t i;
383   char * tp = temp_str;
384   vlc_bool_t saw_control_prefix = false;
385   size_t format_len = strlen(format_str);
386
387   memset(temp_str, 0, TEMP_STR_SIZE);
388
389   for (i=0; i<format_len; i++) {
390
391     if (!saw_control_prefix && format_str[i] != '%') {
392       *tp++ = format_str[i];
393       saw_control_prefix = false;
394       continue;
395     }
396
397     switch(format_str[i]) {
398     case '%':
399       if (saw_control_prefix) {
400         *tp++ = '%';
401       }
402       saw_control_prefix = !saw_control_prefix;
403       break;
404 #ifdef HAVE_LIBCDDB
405     case 'a':
406       if (!p_cdda->b_cddb_enabled) goto not_special;
407       if (p_cdda->cddb.disc)
408         add_format_str_info(p_cdda->cddb.disc->artist);
409       break;
410     case 'A':
411       if (!p_cdda->b_cddb_enabled) goto not_special;
412       if (p_cdda->cddb.disc)
413         add_format_str_info(p_cdda->cddb.disc->title);
414       break;
415     case 'C':
416       if (!p_cdda->b_cddb_enabled) goto not_special;
417       if (p_cdda->cddb.disc)
418         add_format_str_info(CDDB_CATEGORY[p_cdda->cddb.disc->category]);
419       break;
420     case 'G':
421       if (!p_cdda->b_cddb_enabled) goto not_special;
422       if (p_cdda->cddb.disc)
423         add_format_str_info(p_cdda->cddb.disc->genre);
424       break;
425     case 'I':
426       if (!p_cdda->b_cddb_enabled) goto not_special;
427       if (p_cdda->cddb.disc)
428         add_format_num_info(p_cdda->cddb.disc->discid, "%x");
429       break;
430     case 'Y':
431       if (!p_cdda->b_cddb_enabled) goto not_special;
432       if (p_cdda->cddb.disc)
433         add_format_num_info(p_cdda->cddb.disc->year, "%5d");
434       break;
435     case 't':
436       if (p_cdda && p_cdda->b_cddb_enabled && p_cdda->cddb.disc) {
437         cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
438                                             i_track-1);
439         if (t != NULL && t->title != NULL)
440           add_format_str_info(t->title);
441       } else goto not_special;
442       break;
443     case 'p':
444       if (p_cdda->b_cddb_enabled && p_cdda->cddb.disc) {
445         cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
446                                             i_track-1);
447         if (t != NULL && t->artist != NULL)
448           add_format_str_info(t->artist);
449       } else goto not_special;
450       break;
451     case 'e':
452       if (p_cdda->b_cddb_enabled && p_cdda->cddb.disc) {
453         cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc,
454                                             i_track-1);
455         if (t != NULL && t->ext_data != NULL)
456           add_format_str_info(t->ext_data);
457       } else goto not_special;
458       break;
459 #endif
460
461     case 'M':
462       add_format_str_info(mrl);
463       break;
464
465     case 'm':
466       add_format_str_info(p_cdda->psz_mcn);
467       break;
468
469     case 'n':
470       add_format_num_info(p_cdda->i_tracks, "%d");
471       break;
472
473     case 's':
474       if (p_cdda->b_cddb_enabled) {
475         char psz_buffer[MSTRTIME_MAX_SIZE];
476         mtime_t i_duration = (p_cdda->lsn[i_track+1] - p_cdda->lsn[i_track]) 
477           / CDIO_CD_FRAMES_PER_SEC;
478         add_format_str_info(secstotimestr( psz_buffer, i_duration ) );
479       } else goto not_special;
480       break;
481
482     case 'T':
483       add_format_num_info(i_track, "%02d");
484       break;
485 #ifdef HAVE_LIBCDDB
486     not_special:
487 #endif
488     default:
489       *tp++ = '%';
490       *tp++ = format_str[i];
491       saw_control_prefix = false;
492     }
493   }
494   return strdup(temp_str);
495 }
496
497 /* Adds a string-valued entry to the playlist information under "Track"
498    if the string is not null or the null string.
499  */
500 #define add_playlist_track_info_str(TITLE, FIELD)                 \
501   if (FIELD && strlen(FIELD)) {                                   \
502     playlist_ItemAddInfo( p_item, _("Track"), _(TITLE),           \
503                           "%s", FIELD);                           \
504   }  
505
506 void
507 CDDACreatePlaylistItem(const access_t *p_access, cdda_data_t *p_cdda,
508                        playlist_t *p_playlist, track_t i_track,
509                        char *psz_mrl, int psz_mrl_max,
510                        const char *psz_source, int playlist_operation,
511                        int i_pos)
512 {
513   mtime_t i_duration = (p_cdda->lsn[i_track+1] - p_cdda->lsn[i_track])
514     * (1000000 / CDIO_CD_FRAMES_PER_SEC) ;
515   char *psz_title;
516   char *config_varname = MODULE_STRING "-title-format";
517   playlist_item_t *p_item;
518
519 #ifdef HAVE_LIBCDDB
520   if (p_cdda->b_cddb_enabled) {
521     config_varname = MODULE_STRING "-cddb-title-format";
522   }
523 #endif /*HAVE_LIBCDDB*/
524
525   snprintf(psz_mrl, psz_mrl_max, "%s%s@T%u",
526            CDDA_MRL_PREFIX, psz_source, i_track);
527
528   psz_title = CDDAFormatStr(p_access, p_cdda,
529                             config_GetPsz( p_access, config_varname ),
530                             psz_mrl, i_track);
531
532   dbg_print( INPUT_DBG_META, "mrl: %s, title: %s, duration, %ld, pos %d",
533              psz_mrl, psz_title, (long int) i_duration / 1000000 , i_pos );
534   playlist_AddExt( p_playlist, psz_mrl, psz_title, playlist_operation,
535                          i_pos, i_duration , NULL, 0);
536
537   if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
538
539   vlc_mutex_lock( &p_playlist->object_lock );
540   p_item = playlist_ItemGetByPos( p_playlist, i_pos );
541   vlc_mutex_unlock( &p_playlist->object_lock );
542   if( !p_item )
543       return;
544
545   vlc_mutex_lock( &p_item->input.lock );
546
547   add_playlist_track_info_str("Source",  psz_source);
548   playlist_ItemAddInfo( p_item, _("Track"), _("Track Number"), "%d", i_track );
549
550   if (p_cdda->p_cdtext[0]) {
551     const cdtext_t *p = p_cdda->p_cdtext[0];
552     add_playlist_track_info_str("Disc Arranger (CD-Text)",
553                                 p->field[CDTEXT_ARRANGER]);
554     add_playlist_track_info_str("Disc Composer (CD-Text)",
555                                 p->field[CDTEXT_COMPOSER]);
556     add_playlist_track_info_str("Disc ID (CD-Text)",
557                                 p->field[CDTEXT_DISCID]);
558     add_playlist_track_info_str("Disc Genre (CD-Text)",
559                                 p->field[CDTEXT_GENRE]);
560     add_playlist_track_info_str("Disc Message (CD-Text)",
561                                 p->field[CDTEXT_MESSAGE]);
562     add_playlist_track_info_str("Disc Performer (CD-Text)",
563                                 p->field[CDTEXT_PERFORMER]);
564     add_playlist_track_info_str("Disc Songwriter (CD-Text)",
565                                 p->field[CDTEXT_SONGWRITER]);
566     add_playlist_track_info_str("Disc Title (CD-Text)",
567                                 p->field[CDTEXT_TITLE]);
568   }
569
570   if (p_cdda->p_cdtext[i_track]) {
571     const cdtext_t *p = p_cdda->p_cdtext[i_track];
572     add_playlist_track_info_str("Arranger (CD-Text)",
573                                 p->field[CDTEXT_ARRANGER]);
574     add_playlist_track_info_str("Composer (CD-Text)",
575                                 p->field[CDTEXT_COMPOSER]);
576     add_playlist_track_info_str("Genre (CD-Text)",
577                                 p->field[CDTEXT_GENRE]);
578     add_playlist_track_info_str("Message (CD-Text)",
579                                 p->field[CDTEXT_MESSAGE]);
580     add_playlist_track_info_str("Performer (CD-Text)",
581                                 p->field[CDTEXT_PERFORMER]);
582     add_playlist_track_info_str("Songwriter (CD-Text)",
583                                 p->field[CDTEXT_SONGWRITER]);
584     add_playlist_track_info_str("Title (CD-Text)",
585                                 p->field[CDTEXT_TITLE]);
586   }
587   
588
589 #ifdef HAVE_LIBCDDB
590   if (p_cdda->b_cddb_enabled) {
591     cddb_track_t *t=cddb_disc_get_track(p_cdda->cddb.disc, 
592                                         i_track-p_cdda->i_first_track);
593
594     add_playlist_track_info_str("Disc Album (CDDB)",
595                                p_cdda->cddb.disc->title);
596     add_playlist_track_info_str("Disc Artist(s) (CDDB)", 
597                                p_cdda->cddb.disc->artist);
598     add_playlist_track_info_str("Disc Category (CDDB)", 
599                                CDDB_CATEGORY[p_cdda->cddb.disc->category]);
600     add_playlist_track_info_str("Disc Genre (CDDB)", 
601                                p_cdda->cddb.disc->genre);
602     if ( p_cdda->cddb.disc->discid ) {
603       playlist_ItemAddInfo( p_item, _("Track"), _("Disc ID (CDDB)"),
604                             "%x", p_cdda->cddb.disc->discid );
605     }
606     if (p_cdda->cddb.disc->year != 0) {
607       playlist_ItemAddInfo( p_item, _("Track"), _("Year (CDDB)"), 
608                             "%5d", p_cdda->cddb.disc->year );
609     }
610     
611     if (t) {
612       if (t->artist)
613         add_playlist_track_info_str("Track Artist (CDDB)", 
614                                    t->artist);
615       if (t->title)
616         add_playlist_track_info_str("Track Title (CDDB)", 
617                                    t->title);
618     }
619   }
620 #endif /*HAVE_LIBCDDB*/
621
622   vlc_mutex_unlock( &p_item->input.lock );
623 }
624
625 int
626 CDDAFixupPlaylist( access_t *p_access, cdda_data_t *p_cdda, 
627                    const char *psz_source, vlc_bool_t b_single_track )
628 {
629   int i;
630   playlist_t * p_playlist;
631   char       * psz_mrl;
632   unsigned int psz_mrl_max = strlen(CDDA_MRL_PREFIX) + strlen(psz_source) +
633     strlen("@T") + strlen("100") + 1;
634   const track_t i_first_track = p_cdda->i_first_track;
635
636 #ifdef HAVE_LIBCDDB
637   p_cdda->b_cddb_enabled =
638     config_GetInt( p_access, MODULE_STRING "-cddb-enabled" );
639   if( b_single_track && !p_cdda->b_cddb_enabled ) return VLC_SUCCESS;
640 #else
641   if( b_single_track ) return VLC_SUCCESS;
642 #endif
643
644   psz_mrl = malloc( psz_mrl_max );
645
646   if( psz_mrl == NULL )
647     {
648       msg_Warn( p_access, "out of memory" );
649       return VLC_ENOMEM;
650     }
651
652   p_playlist = (playlist_t *) vlc_object_find( p_access, VLC_OBJECT_PLAYLIST,
653                                                FIND_ANYWHERE );
654   if( !p_playlist )
655     {
656       msg_Warn( p_access, "can't find playlist" );
657       free(psz_mrl);
658       return VLC_EGENERIC;
659     }
660
661   CDDAMetaInfo(p_access);
662
663   if (b_single_track) {
664     /* May fill out more information when the playlist user interface becomes
665        more mature.
666      */
667     track_t i_track = p_cdda->i_track;
668
669     input_title_t *t = p_cdda->p_title[i_track-i_first_track] = 
670       vlc_input_title_New();
671         
672     asprintf( &t->psz_name, _("Track %i"), i_track );
673     t->i_size = p_access->info.i_size =
674       ( p_cdda->lsn[i_track+1] - p_cdda->lsn[i_track] ) * 
675       (int64_t) CDIO_CD_FRAMESIZE_RAW;
676         
677     t->i_length = I64C(1000000) * t->i_size / CDDA_FREQUENCY_SAMPLE / 4;
678     CDDACreatePlaylistItem(p_access, p_cdda, p_playlist, i_track,
679                            psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
680                            p_playlist->i_index);
681     p_cdda->i_titles = 1;
682   } else {
683
684     for( i = 0 ; i < p_cdda->i_tracks ; i++ )
685       {
686         const track_t i_track = i_first_track + i;
687         input_title_t *t = p_cdda->p_title[i] = vlc_input_title_New();
688         
689         asprintf( &t->psz_name, _("Track %i"), i_track );
690         t->i_size = ( p_cdda->lsn[i_track+1] - p_cdda->lsn[i_track] ) *
691           (int64_t) CDIO_CD_FRAMESIZE_RAW;
692         
693         t->i_length = I64C(1000000) * t->i_size / CDDA_FREQUENCY_SAMPLE / 4;
694         CDDACreatePlaylistItem(p_access, p_cdda, p_playlist, i_track, 
695                                psz_mrl, psz_mrl_max, psz_source, 
696                                PLAYLIST_APPEND, PLAYLIST_END);
697       }
698     p_cdda->i_titles = p_cdda->i_tracks; /* should be +1 */
699     p_access->info.i_size = 
700       (p_cdda->lsn[i_first_track + p_cdda->i_tracks] 
701        - p_cdda->lsn[i_first_track]) * (int64_t) CDIO_CD_FRAMESIZE_RAW;
702   }
703
704   return VLC_SUCCESS;
705 }
706