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