]> git.sesse.net Git - vlc/blob - modules/access/vcdx/access.c
Allow PBC selection. Had been temporarily disabled. Perhaps this is
[vlc] / modules / access / vcdx / access.c
1 /*****************************************************************************
2  * vcd.c : VCD input module for vlc
3  *         using libcdio, libvcd and libvcdinfo. vlc-specific things tend
4  *         to go here.
5  *****************************************************************************
6  * Copyright (C) 2000, 2003, 2004 VideoLAN
7  * $Id: access.c,v 1.17 2004/01/25 04:53:16 rocky Exp $
8  *
9  * Authors: Rocky Bernstein <rocky@panix.com>
10  *          Johan Bilien <jobi@via.ecp.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/intf.h>
34
35 #include "../../demux/mpeg/system.h"
36 #include "vcd.h"
37 #include "vcdplayer.h"
38 #include "intf.h"
39
40 #include <cdio/cdio.h>
41 #include <cdio/cd_types.h>
42 #include <cdio/logging.h>
43 #include <cdio/util.h>
44 #include <libvcd/info.h>
45 #include <libvcd/logging.h>
46
47 #include "cdrom.h"
48
49 /* how many blocks VCDRead will read in each loop */
50 #define VCD_BLOCKS_ONCE 20
51 #define VCD_DATA_ONCE   (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)
52
53 #define VCD_MRL_PREFIX "vcdx://"
54
55 /*****************************************************************************
56  * Local prototypes
57  *****************************************************************************/
58
59 /* First those which are accessed from outside (via pointers). */
60 static int  VCDRead         ( input_thread_t *, byte_t *, size_t );
61 static int  VCDSetProgram   ( input_thread_t *, pgrm_descriptor_t * );
62
63 /* Now those which are strictly internal */
64 static void VCDSetOrigin    ( input_thread_t *, lsn_t origin_lsn,
65                               lsn_t cur_lsn, lsn_t end_lsn,
66                               int cur_entry, track_t track );
67 static int  VCDEntryPoints  ( input_thread_t * );
68 static int  VCDLIDs         ( input_thread_t * );
69 static int  VCDSegments     ( input_thread_t * );
70 static void VCDTracks       ( input_thread_t * );
71 static int  VCDReadSector   ( vlc_object_t *p_this,
72                               const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn,
73                               byte_t * p_buffer );
74 static char *VCDParse       ( input_thread_t *,
75                               /*out*/ vcdinfo_itemid_t * p_itemid ,
76                               /*out*/ bool *play_single_item );
77
78 static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
79                           const char *p_varname, char *p_label,
80                           const char *p_debug_label );
81
82 static vcdinfo_obj_t *vcd_Open   ( vlc_object_t *p_this, const char *psz_dev );
83
84 /****************************************************************************
85  * Private functions
86  ****************************************************************************/
87
88 /* FIXME: This variable is a hack. Would be nice to eliminate the
89    global-ness. */
90
91 static input_thread_t *p_vcd_input = NULL;
92
93 /* process messages that originate from libcdio. */
94 static void
95 cdio_log_handler (cdio_log_level_t level, const char message[])
96 {
97   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
98   switch (level) {
99   case CDIO_LOG_DEBUG:
100   case CDIO_LOG_INFO:
101     if (p_vcd->i_debug & INPUT_DBG_CDIO)
102       msg_Dbg( p_vcd_input, message);
103     break;
104   case CDIO_LOG_WARN:
105     msg_Warn( p_vcd_input, message);
106     break;
107   case CDIO_LOG_ERROR:
108   case CDIO_LOG_ASSERT:
109     msg_Err( p_vcd_input, message);
110     break;
111   default:
112     msg_Warn( p_vcd_input, message,
113             _("The above message had unknown log level"),
114             level);
115   }
116   return;
117 }
118
119 /* process messages that originate from vcdinfo. */
120 static void
121 vcd_log_handler (vcd_log_level_t level, const char message[])
122 {
123   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
124   switch (level) {
125   case VCD_LOG_DEBUG:
126   case VCD_LOG_INFO:
127     if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
128       msg_Dbg( p_vcd_input, message);
129     break;
130   case VCD_LOG_WARN:
131     msg_Warn( p_vcd_input, message);
132     break;
133   case VCD_LOG_ERROR:
134   case VCD_LOG_ASSERT:
135     msg_Err( p_vcd_input, message);
136     break;
137   default:
138     msg_Warn( p_vcd_input, "%s\n%s %d", message,
139             _("The above message had unknown vcdimager log level"),
140             level);
141   }
142   return;
143 }
144
145 /*****************************************************************************
146  * VCDRead: reads i_len bytes from the VCD into p_buffer.
147  *****************************************************************************
148  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
149  * bytes.
150  *****************************************************************************/
151 static int
152 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
153 {
154     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
155     int                     i_blocks;
156     int                     i_index;
157     int                     i_read;
158     byte_t                  p_last_sector[ M2F2_SECTOR_SIZE ];
159
160     i_read = 0;
161
162     dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn );
163
164     /* Compute the number of blocks we have to read */
165
166     i_blocks = i_len / M2F2_SECTOR_SIZE;
167
168     for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
169     {
170
171       if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
172         vcdplayer_read_status_t read_status;
173
174         /* We've run off of the end of this entry. Do we continue or stop? */
175         dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
176                    "end reached, cur: %u", p_vcd->cur_lsn );
177
178         read_status = vcdplayer_pbc_is_on( p_vcd )
179           ? vcdplayer_pbc_nav( p_input )
180           : vcdplayer_non_pbc_nav( p_input );
181
182         switch (read_status) {
183         case READ_END:
184           /* End reached. Return NULL to indicated this. */
185         case READ_ERROR:
186           /* Some sort of error. */
187           return i_read;
188
189         case READ_STILL_FRAME:
190           {
191             /* Reached the end of a still frame. */
192
193             byte_t * p_buf = p_buffer;
194             pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
195
196             p_buf += (i_index*M2F2_SECTOR_SIZE);
197             memset(p_buf, 0, M2F2_SECTOR_SIZE);
198             p_buf += 2;
199             *p_buf = 0x01;
200             dbg_print(INPUT_DBG_STILL, "Handled still event");
201
202 #if 1
203             p_vcd->p_intf->p_sys->b_still = 1;
204             input_SetStatus( p_input, INPUT_STATUS_PAUSE );
205 #endif
206
207             vlc_mutex_lock( &p_input->stream.stream_lock );
208
209             p_pgrm = p_input->stream.p_selected_program;
210             p_pgrm->i_synchro_state = SYNCHRO_REINIT;
211
212             vlc_mutex_unlock( &p_input->stream.stream_lock );
213
214             input_ClockManageControl( p_input, p_pgrm, 0 );
215
216             p_vcd->p_intf->p_sys->b_still = 1;
217             input_SetStatus( p_input, INPUT_STATUS_PAUSE );
218
219             return i_read + M2F2_SECTOR_SIZE;
220           }
221         default:
222         case READ_BLOCK:
223           break;
224         }
225       }
226
227       if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
228                           p_vcd->cur_lsn,
229                           p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
230         {
231           LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
232           return -1;
233         }
234
235       p_vcd->cur_lsn ++;
236
237       /* Update chapter */
238       if( p_vcd->b_valid_ep &&
239           /* FIXME kludge so that read does not update chapter
240            * when a manual chapter change was requested and not
241            * yet accomplished */
242           !p_input->stream.p_new_area )
243         {
244           unsigned int i_entry = p_input->stream.p_selected_area->i_part;
245
246           vlc_mutex_lock( &p_input->stream.stream_lock );
247
248           if( i_entry < p_vcd->num_entries &&
249               p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
250             {
251               dbg_print( INPUT_DBG_PBC,
252                          "new entry, i_entry %d, sector %d, es %d",
253                          i_entry, p_vcd->cur_lsn,
254                          p_vcd->p_entries[i_entry] );
255               p_vcd->play_item.num =
256                 ++ p_input->stream.p_selected_area->i_part;
257               p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
258               VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
259                             "chapter", _("Entry"), "Setting entry" );
260             }
261           vlc_mutex_unlock( &p_input->stream.stream_lock );
262         }
263
264         i_read += M2F2_SECTOR_SIZE;
265     }
266
267     if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
268     {
269         if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
270                             p_vcd->cur_lsn, p_last_sector ) < 0 )
271         {
272             LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
273             return -1;
274         }
275
276         p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
277                                    p_last_sector, i_len % M2F2_SECTOR_SIZE );
278         i_read += i_len % M2F2_SECTOR_SIZE;
279     }
280
281     return i_read;
282 }
283
284
285 /*****************************************************************************
286  * VCDSetProgram: Does nothing since a VCD is mono_program
287  *****************************************************************************/
288 static int
289 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
290 {
291     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
292     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
293     return 0;
294 }
295
296
297 /*****************************************************************************
298  * VCDSetArea: initialize internal data structures and input stream data
299    so set subsequent reading and seeking to reflect that we are
300    at track x, entry or segment y.
301    This is called for each user navigation request, e.g. the GUI
302    Chapter/Title selections or in initial MRL parsing.
303  ****************************************************************************/
304 int
305 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
306 {
307     thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
308     unsigned int i_entry = p_area->i_part;
309     track_t i_track      = p_area->i_id;
310     int old_seekable     = p_input->stream.b_seekable;
311     unsigned int i_nb    = p_area->i_plugin_data + p_area->i_part_nb;
312
313     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
314                "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
315                i_track, i_entry, old_seekable,
316                (long unsigned int) p_area,
317                (long unsigned int) p_input->stream.p_selected_area );
318
319     /* we can't use the interface slider until initilization is complete */
320     p_input->stream.b_seekable = 0;
321
322     if( p_area != p_input->stream.p_selected_area )
323     {
324         unsigned int i;
325
326         /* If is the result of a track change, make the entry valid. */
327         if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
328           i_entry = p_area->i_plugin_data;
329
330         /* Change the default area */
331         p_input->stream.p_selected_area = p_area;
332
333         /* Update the navigation variables without triggering a callback */
334
335         VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
336                       _("Track"), "Setting track");
337
338         var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
339         for( i = p_area->i_plugin_data; i < i_nb; i++ )
340         {
341           VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
342                         "chapter",  
343                         p_vcd->play_item.type == VCDINFO_ITEM_TYPE_ENTRY ?
344                         _("Entry") : _("Segment"), 
345                         "Adding entry choice");
346         }
347
348         if (p_vcd->b_svd) {
349           unsigned int audio_type = 
350             vcdinfo_get_track_audio_type(p_vcd->vcd, i_track);
351           unsigned int i_channels = 
352             vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type);
353           
354           var_Change( p_input, "audio_channels", VLC_VAR_CLEARCHOICES, NULL, 
355                       NULL );
356           
357           for( i = 0;  i < i_channels; i++ )
358             {
359               VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
360                             "audio_channels",  NULL, "Adding audio choice");
361             }
362         }
363
364     }
365
366     if (i_track == 0)
367       VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
368                     p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
369                     i_entry, 0 );
370     else
371       VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
372                     vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
373                     p_vcd->p_sectors[i_track+1],
374                     i_entry, i_track );
375
376     p_input->stream.b_seekable = old_seekable;
377     /* warn interface that something has changed */
378     p_input->stream.b_changed = 1;
379
380     return VLC_SUCCESS;
381 }
382
383
384 /****************************************************************************
385  * VCDSeek
386  ****************************************************************************/
387 void
388 VCDSeek( input_thread_t * p_input, off_t i_off )
389 {
390     thread_vcd_data_t * p_vcd;
391     unsigned int i_entry=0; /* invalid entry */
392
393     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
394
395     p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
396
397     vlc_mutex_lock( &p_input->stream.stream_lock );
398 #define p_area p_input->stream.p_selected_area
399     /* Find entry */
400     if( p_vcd->b_valid_ep )
401     {
402         for( i_entry = 0 ; i_entry < p_vcd->num_entries ; i_entry ++ )
403         {
404             if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
405             {
406               VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
407                             "chapter", _("Entry"), "Setting entry" );
408               break;
409             }
410         }
411         p_vcd->play_item.num  = p_area->i_part = i_entry;
412         p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
413     }
414 #undef p_area
415
416     p_input->stream.p_selected_area->i_tell = i_off;
417
418     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
419     "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
420                p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
421                p_input->stream.p_selected_area->i_start, i_entry );
422
423     vlc_mutex_unlock( &p_input->stream.stream_lock );
424 }
425
426 /*****************************************************************************
427   VCDPlay: set up internal structures so seeking/reading places an item.
428   itemid: the thing to play.
429   user_entry: true if itemid is a user selection (rather than internally-
430   generated selection such as via PBC) in which case we may have to adjust
431   for differences in numbering.
432  *****************************************************************************/
433 int
434 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
435 {
436     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
437     input_area_t *          p_area;
438     bool                    b_was_still;
439
440     dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
441               itemid.num, itemid.type);
442
443     if (!p_input->p_access_data) return VLC_EGENERIC;
444     
445     b_was_still = p_vcd->in_still;
446
447 #define area p_input->stream.pp_areas
448
449     switch (itemid.type) {
450     case VCDINFO_ITEM_TYPE_TRACK:
451
452       /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
453        */
454
455       if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
456         LOG_ERR ("Invalid track number %d", itemid.num );
457         return VLC_EGENERIC;
458       }
459       p_vcd->in_still  = false;
460       p_area           = area[itemid.num];
461       p_area->i_part   = p_area->i_plugin_data;
462       p_input->stream.b_seekable = 1;
463       break;
464     case VCDINFO_ITEM_TYPE_SEGMENT:
465       /* Valid segments go from 0...num_segments-1. */
466       if (itemid.num >= p_vcd->num_segments) {
467         LOG_ERR ( "Invalid segment number: %d", itemid.num );
468         return VLC_EGENERIC;
469       } else {
470         vcdinfo_video_segment_type_t segtype =
471           vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
472
473         dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
474                   vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
475                   (int) segtype, itemid.num);
476
477         p_area           = area[0];
478         p_area->i_part   = itemid.num;
479
480         switch (segtype)
481           {
482           case VCDINFO_FILES_VIDEO_NTSC_STILL:
483           case VCDINFO_FILES_VIDEO_NTSC_STILL2:
484           case VCDINFO_FILES_VIDEO_PAL_STILL:
485           case VCDINFO_FILES_VIDEO_PAL_STILL2:
486             p_input->stream.b_seekable = 0;
487             p_vcd->in_still = true;
488             break;
489           default:
490             p_input->stream.b_seekable = 1;
491             p_vcd->in_still = false;
492           }
493       }
494       break;
495
496     case VCDINFO_ITEM_TYPE_LID:
497       /* LIDs go from 1..num_lids. */
498       if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
499         LOG_ERR ( "Invalid LID number: %d", itemid.num );
500         return VLC_EGENERIC;
501       } else {
502         p_vcd->cur_lid = itemid.num;
503         vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
504
505         switch (p_vcd->pxd.descriptor_type) {
506
507         case PSD_TYPE_SELECTION_LIST:
508         case PSD_TYPE_EXT_SELECTION_LIST: {
509           vcdinfo_itemid_t trans_itemid;
510           uint16_t trans_itemid_num;
511
512           if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
513           trans_itemid_num  = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
514           vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
515           p_vcd->loop_count = 1;
516           p_vcd->loop_item  = trans_itemid;
517           return VCDPlay( p_input, trans_itemid );
518           break;
519         }
520
521         case PSD_TYPE_PLAY_LIST: {
522           if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
523           p_vcd->pdi = -1;
524           return vcdplayer_inc_play_item(p_input)
525             ? VLC_SUCCESS : VLC_EGENERIC;
526           break;
527         }
528
529         case PSD_TYPE_END_LIST:
530         case PSD_TYPE_COMMAND_LIST:
531
532         default:
533           ;
534         }
535       }
536       return VLC_EGENERIC;
537     case VCDINFO_ITEM_TYPE_ENTRY:
538       /* Entries go from 0..num_entries-1. */
539       if (itemid.num >= p_vcd->num_entries) {
540         LOG_ERR ("Invalid entry number: %d", itemid.num );
541         return VLC_EGENERIC;
542       } else {
543         track_t cur_track  = vcdinfo_get_track(p_vcd->vcd,  itemid.num);
544         p_vcd->in_still    = false;
545         p_area             = area[cur_track];
546         p_area->i_part     = itemid.num;
547         p_input->stream.b_seekable = 1;
548       }
549       break;
550     default:
551       LOG_ERR ("unknown entry type" );
552       return VLC_EGENERIC;
553     }
554
555     VCDSetArea( p_input, p_area );
556
557 #undef area
558
559 #if 1
560     if ( p_vcd->in_still != b_was_still ) {
561       if (p_input->stream.pp_selected_es) {
562         input_SetStatus( p_input, INPUT_STATUS_END );
563         input_SetStatus( p_input, INPUT_STATUS_PLAY );
564       }
565     }
566 #endif
567
568     p_vcd->play_item = itemid;
569
570     dbg_print( (INPUT_DBG_CALL),
571                "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
572                p_area->i_start, p_area->i_size,
573                p_area->i_tell, p_vcd->cur_lsn );
574
575     return VLC_SUCCESS;
576 }
577
578 /*****************************************************************************
579   VCDEntryPoints: Reads the information about the entry points on the disc
580   and initializes area information with that.
581   Before calling this track information should have been read in.
582  *****************************************************************************/
583 static int
584 VCDEntryPoints( input_thread_t * p_input )
585 {
586     thread_vcd_data_t *               p_vcd;
587     unsigned int                      i_nb;
588     unsigned int                      i, i_entry_index = 0;
589     unsigned int                      i_previous_track = CDIO_INVALID_TRACK;
590
591     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
592
593     i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
594     if (0 == i_nb)
595       return -1;
596
597     p_vcd->p_entries  = malloc( sizeof( lba_t ) * i_nb );
598
599     if( p_vcd->p_entries == NULL )
600     {
601         LOG_ERR ("not enough memory for entry points treatment" );
602         return -1;
603     }
604
605     p_vcd->num_entries = 0;
606
607     for( i = 0 ; i < i_nb ; i++ )
608     {
609         track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
610         if( i_track <= p_input->stream.i_area_nb )
611         {
612             p_vcd->p_entries[i] =
613               vcdinfo_get_entry_lsn(p_vcd->vcd, i);
614             p_input->stream.pp_areas[i_track]->i_part_nb ++;
615
616             /* if this entry belongs to a new track */
617             if( i_track != i_previous_track )
618             {
619                 /* i_plugin_data is used to store the first entry of the area*/
620                 p_input->stream.pp_areas[i_track]->i_plugin_data =
621                                                             i_entry_index;
622                 i_previous_track = i_track;
623                 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
624             }
625             i_entry_index ++;
626             p_vcd->num_entries ++;
627         }
628         else
629             msg_Warn( p_input, "wrong track number found in entry points" );
630     }
631     p_vcd->b_valid_ep = true;
632     return 0;
633 }
634
635 /*****************************************************************************
636  * VCDSegments: Reads the information about the segments the disc.
637  *****************************************************************************/
638 static int
639 VCDSegments( input_thread_t * p_input )
640 {
641     thread_vcd_data_t * p_vcd;
642     unsigned int        i;
643     unsigned int        num_segments;
644
645
646     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
647     num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
648
649 #define area p_input->stream.pp_areas
650
651     /* area 0 is reserved for segments. Set Absolute start offset
652          and size */
653     area[0]->i_plugin_data = 0;
654     input_DelArea( p_input, area[0] );
655     input_AddArea( p_input, 0, 0 );
656
657     area[0]->i_start = (off_t)p_vcd->p_sectors[0]
658       * (off_t)M2F2_SECTOR_SIZE;
659     area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
660       * (off_t)M2F2_SECTOR_SIZE;
661
662     /* Default Segment  */
663     area[0]->i_part = 0;
664
665     /* i_plugin_data is used to store which entry point is the first
666        of the track (area) */
667     area[0]->i_plugin_data = 0;
668
669     area[0]->i_part_nb = 0;
670
671     dbg_print( INPUT_DBG_MRL,
672                "area[0] id: %d, i_start: %lld, i_size: %lld",
673                area[0]->i_id, area[0]->i_start, area[0]->i_size );
674
675     if (num_segments == 0) return 0;
676
677     /* We have one additional segment allocated so we can get the size
678        by subtracting seg[i+1] - seg[i].
679      */
680     p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
681     if( p_vcd->p_segments == NULL )
682     {
683         LOG_ERR ("not enough memory for segment treatment" );
684         return -1;
685     }
686
687     /* Update the navigation variables without triggering a callback */
688     VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", _("Track"),
689                   "Setting track" );
690
691     var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
692
693     for( i = 0 ; i < num_segments ; i++ )
694     {
695       p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
696       area[0]->i_part_nb ++;
697       VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
698                     "chapter", _("Segment"), "Adding segment choice");
699     }
700
701 #undef area
702
703     p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
704       vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
705
706     return 0;
707 }
708
709 /*****************************************************************************
710  VCDTracks: initializes area information.
711  Before calling this track information should have been read in.
712  *****************************************************************************/
713 static void
714 VCDTracks( input_thread_t * p_input )
715 {
716     thread_vcd_data_t * p_vcd;
717     unsigned int        i;
718
719     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
720
721 #define area p_input->stream.pp_areas
722
723     /* We start area addressing for tracks at 1 since the default area 0
724        is reserved for segments */
725
726     for( i = 1 ; i < p_vcd->num_tracks ; i++ )
727     {
728         /* Tracks are Program Chains */
729         input_AddArea( p_input, i, i );
730
731         /* Absolute start byte offset and byte size */
732         area[i]->i_start = (off_t) p_vcd->p_sectors[i]
733                            * (off_t)M2F2_SECTOR_SIZE;
734         area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
735                            * (off_t)M2F2_SECTOR_SIZE;
736
737         /* Current entry being played in track */
738         area[i]->i_part = 0;
739
740         /* i_plugin_data is used to store which entry point is the first
741          * of the track (area) */
742         area[i]->i_plugin_data = 0;
743
744         dbg_print( INPUT_DBG_MRL,
745                    "area[%d] id: %d, i_start: %lld, i_size: %lld",
746                    i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
747     }
748
749 #undef area
750
751     return ;
752 }
753
754 /*****************************************************************************
755   VCDLIDs: Reads the LIST IDs from the LOT.
756  *****************************************************************************/
757 static int
758 VCDLIDs( input_thread_t * p_input )
759 {
760     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
761
762     p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
763     p_vcd->cur_lid  = VCDINFO_INVALID_ENTRY;
764
765     if (vcdinfo_read_psd (p_vcd->vcd)) {
766
767       vcdinfo_visit_lot (p_vcd->vcd, false);
768
769 #if FIXED
770     /*
771        We need to change libvcdinfo to be more robust when there are
772        problems reading the extended PSD. Given that area-highlighting and
773        selection features in the extended PSD haven't been implemented,
774        it's best then to not try to read this at all.
775      */
776       if (vcdinfo_get_psd_x_size(p_vcd->vcd))
777         vcdinfo_visit_lot (p_vcd->vcd, true);
778 #endif
779     }
780
781     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
782                "num LIDs=%d", p_vcd->num_lids);
783
784     return 0;
785 }
786
787 /*****************************************************************************
788  * VCDParse: parse command line
789  *****************************************************************************/
790 static char *
791 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
792           /*out*/ bool *play_single_item )
793 {
794     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
795     char *             psz_parser;
796     char *             psz_source;
797     char *             psz_next;
798
799     if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
800       p_itemid->type=VCDINFO_ITEM_TYPE_LID;
801       p_itemid->num=1;
802       *play_single_item=false;
803     } else {
804       p_itemid->type=VCDINFO_ITEM_TYPE_ENTRY;
805       p_itemid->num=0;
806     }
807
808 #ifdef WIN32
809     /* On Win32 we want the VCD access plugin to be explicitly requested,
810      * we end up with lots of problems otherwise */
811     if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
812 #endif
813
814     if( !p_input->psz_name )
815     {
816         return NULL;
817     }
818
819     psz_parser = psz_source = strdup( p_input->psz_name );
820
821     /* Parse input string :
822      * [device][@[type][title]] */
823     while( *psz_parser && *psz_parser != '@' )
824     {
825         psz_parser++;
826     }
827
828     if( *psz_parser == '@' )
829     {
830       /* Found the divide between the source name and the
831          type+entry number. */
832       unsigned int num;
833
834       *psz_parser = '\0';
835       ++psz_parser;
836       if( *psz_parser )
837         {
838           switch(*psz_parser) {
839           case 'E':
840             p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
841             ++psz_parser;
842             *play_single_item = true;
843             break;
844           case 'P':
845             p_itemid->type = VCDINFO_ITEM_TYPE_LID;
846             ++psz_parser;
847             *play_single_item = false;
848             break;
849           case 'S':
850             p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
851             ++psz_parser;
852             *play_single_item = true;
853             break;
854           case 'T':
855             p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
856             ++psz_parser;
857             *play_single_item = true;
858             break;
859           default: ;
860           }
861         }
862
863       num = strtol( psz_parser, &psz_next, 10 );
864       if ( *psz_parser != '\0' && *psz_next == '\0')
865         {
866           p_itemid->num = num;
867         }
868
869     } else {
870       *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
871     }
872
873
874     if( !*psz_source ) {
875
876       /* No source specified, so figure it out. */
877       if( !p_input->psz_access ) return NULL;
878
879       psz_source = config_GetPsz( p_input, "vcd" );
880
881       if( !psz_source || 0==strlen(psz_source) ) {
882         /* Scan for a CD-ROM drive with a VCD in it. */
883         char **cd_drives = cdio_get_devices_with_cap(NULL,
884                             (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
885                              |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
886                                                      true);
887         if (NULL == cd_drives) return NULL;
888         if (cd_drives[0] == NULL) {
889           cdio_free_device_list(cd_drives);
890           return NULL;
891         }
892         psz_source = strdup(cd_drives[0]);
893         cdio_free_device_list(cd_drives);
894       }
895     }
896
897     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
898                "source=%s entry=%d type=%d",
899                psz_source, p_itemid->num, p_itemid->type);
900
901     return psz_source;
902 }
903
904 /*
905    Set's start origin subsequent seeks/reads
906 */
907 static void
908 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
909               lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
910 {
911   thread_vcd_data_t * p_vcd  = (thread_vcd_data_t *) p_input->p_access_data;
912
913   p_vcd->origin_lsn = origin_lsn;
914   p_vcd->cur_lsn    = cur_lsn;
915   p_vcd->end_lsn    = end_lsn;
916   p_vcd->cur_track  = cur_track;
917   p_vcd->play_item.num  = cur_entry;
918   p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
919
920   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
921              "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
922              origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
923
924   p_input->stream.p_selected_area->i_tell =
925     (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
926
927   VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
928                 "chapter", 
929                 p_vcd->play_item.type == VCDINFO_ITEM_TYPE_ENTRY ?
930                 _("Entry") : _("Segment"), 
931                 "Setting entry/segment");
932 }
933
934 /*****************************************************************************
935  * vcd_Open: Opens a VCD device or file and returns an opaque handle
936  *****************************************************************************/
937 static vcdinfo_obj_t *
938 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
939 {
940     vcdinfo_obj_t *p_vcdobj;
941     char  *actual_dev;
942
943     if( !psz_dev ) return NULL;
944
945     actual_dev=strdup(psz_dev);
946     if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
947          VCDINFO_OPEN_VCD) {
948       free(actual_dev);
949       return NULL;
950     }
951     free(actual_dev);
952
953     return p_vcdobj;
954 }
955
956 /****************************************************************************
957  * VCDReadSector: Read a sector (2324 bytes)
958  ****************************************************************************/
959 static int
960 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
961                lsn_t cur_lsn, byte_t * p_buffer )
962 {
963   typedef struct {
964     uint8_t subheader   [8];
965     uint8_t data        [M2F2_SECTOR_SIZE];
966   } vcdsector_t;
967   vcdsector_t vcd_sector;
968
969   if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
970                              &vcd_sector, cur_lsn, true)
971       != 0)
972     {
973       msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
974       return -1;
975     }
976
977   memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
978
979   return( 0 );
980 }
981
982 /****************************************************************************
983  Update the "varname" variable to i_num without triggering a callback.
984 ****************************************************************************/
985 static void
986 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
987               const char *p_varname, char *p_label, 
988               const char *p_debug_label)
989 {
990   vlc_value_t val;
991   val.i_int = i_num;
992   if (NULL != p_vcd_input) {
993     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
994     dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
995   }
996   if (p_label) {
997     vlc_value_t text;
998     text.psz_string = p_label;
999     var_Change( p_input, p_varname, VLC_VAR_SETTEXT, &text, NULL );
1000   }
1001   var_Change( p_input, p_varname, i_action, &val, NULL );
1002 }
1003
1004
1005 static inline void
1006 MetaInfoAddStr(input_thread_t *p_input, input_info_category_t *p_cat, 
1007                   playlist_t *p_playlist, char *title, 
1008                   const char *str)
1009 {
1010   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1011   if ( str ) {                                                                
1012     dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str);
1013     input_AddInfo( p_cat, title, "%s", str );              
1014     playlist_AddInfo( p_playlist, -1, p_cat->psz_name, title,
1015                       "%s",str );                                             
1016   }
1017 }
1018
1019
1020 static inline void
1021 MetaInfoAddNum(input_thread_t *p_input, input_info_category_t *p_cat, 
1022                playlist_t *p_playlist, char *title, int num)
1023 {
1024   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1025   dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num);
1026   input_AddInfo( p_cat, title, "%d", num );
1027   playlist_AddInfo( p_playlist, -1, p_cat->psz_name, title,
1028                     "%d",num );
1029 }
1030   
1031 #define addstr(title, str) \
1032   MetaInfoAddStr( p_input, p_cat, p_playlist, title, str );
1033
1034 #define addnum(title, num) \
1035   MetaInfoAddNum( p_input, p_cat, p_playlist, title, num );
1036   
1037 static void InformationCreate( input_thread_t *p_input  )
1038 {
1039   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1040   unsigned int i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
1041   unsigned int last_entry = 0;
1042   input_info_category_t *p_cat;
1043   track_t i_track;
1044   playlist_t *p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1045                                                  FIND_PARENT );
1046
1047   p_cat = input_InfoCategory( p_input, "General" );
1048
1049   addstr( _("VCD Format"),  vcdinfo_get_format_version_str(p_vcd->vcd) );
1050   addstr( _("Album"),       vcdinfo_get_album_id(p_vcd->vcd));
1051   addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
1052   addstr( _("Preparer"),    vcdinfo_get_preparer_id(p_vcd->vcd) );
1053   addnum( _("Vol #"),       vcdinfo_get_volume_num(p_vcd->vcd) );
1054   addnum( _("Vol max #"),   vcdinfo_get_volume_count(p_vcd->vcd) );
1055   addstr( _("Volume Set"),  vcdinfo_get_volumeset_id(p_vcd->vcd) );
1056   addstr( _("Volume"),      vcdinfo_get_volume_id(p_vcd->vcd) );
1057   addstr( _("Publisher"),   vcdinfo_get_publisher_id(p_vcd->vcd) );
1058   addstr( _("System Id"),   vcdinfo_get_system_id(p_vcd->vcd) );
1059   addnum( "LIDs",           vcdinfo_get_num_LIDs(p_vcd->vcd) );
1060   addnum( _("Entries"),     vcdinfo_get_num_entries(p_vcd->vcd) );
1061   addnum( _("Segments"),    vcdinfo_get_num_segments(p_vcd->vcd) );
1062   addnum( _("Tracks"),      vcdinfo_get_num_tracks(p_vcd->vcd) );
1063
1064   /* Spit out track information. Could also include MSF info.
1065    */
1066
1067 #define TITLE_MAX 30
1068   for( i_track = 1 ; i_track < p_vcd->num_tracks ; i_track++ ) {
1069     char track_str[TITLE_MAX];
1070     unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd, 
1071                                                            i_track);
1072     snprintf(track_str, TITLE_MAX, "%s%02d", _("Track"), i_track);
1073     p_cat = input_InfoCategory( p_input, track_str );
1074
1075     if (p_vcd->b_svd) {
1076       addnum(_("Audio Channels"),  
1077              vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
1078     }
1079
1080     addnum(_("First Entry Point"), last_entry );
1081     for ( ; last_entry < i_nb 
1082             && vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
1083           last_entry++ ) ;
1084     addnum(_("Last Entry Point"), last_entry-1 );
1085   }
1086 }
1087
1088 #define add_format_str_info(val)                               \
1089   {                                                            \
1090     const char *str = val;                                     \
1091     unsigned int len;                                          \
1092     if (val != NULL) {                                         \
1093       len=strlen(str);                                         \
1094       if (len != 0) {                                          \
1095         strncat(tp, str, TEMP_STR_LEN-(tp-temp_str));          \
1096         tp += len;                                             \
1097       }                                                        \
1098       saw_control_prefix = false;                              \
1099     }                                                          \
1100   }
1101
1102 #define add_format_num_info(val, fmt)                          \
1103   {                                                            \
1104     char num_str[10];                                          \
1105     unsigned int len;                                          \
1106     sprintf(num_str, fmt, val);                                \
1107     len=strlen(num_str);                                       \
1108     if (len != 0) {                                            \
1109       strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));        \
1110       tp += len;                                               \
1111     }                                                          \
1112     saw_control_prefix = false;                                \
1113   }
1114
1115 /*!
1116    Take a format string and expand escape sequences, that is sequences that
1117    begin with %, with information from the current VCD.
1118    The expanded string is returned. Here is a list of escape sequences:
1119
1120    %A : The album information
1121    %C : The VCD volume count - the number of CD's in the collection.
1122    %c : The VCD volume num - the number of the CD in the collection.
1123    %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
1124    %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
1125    %L : The playlist ID prefixed with " LID" if it exists
1126    %M : MRL
1127    %N : The current number of the %I - a decimal number
1128    %P : The publisher ID
1129    %p : The preparer ID
1130    %S : If we are in a segment (menu), the kind of segment
1131    %T : The track number
1132    %V : The volume set ID
1133    %v : The volume ID
1134        A number between 1 and the volume count.
1135    %% : a %
1136 */
1137 static char *
1138 VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1139              const char format_str[], const char *mrl,
1140              const vcdinfo_itemid_t *itemid)
1141 {
1142 #define TEMP_STR_SIZE 256
1143 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
1144   static char    temp_str[TEMP_STR_SIZE];
1145   size_t i;
1146   char * tp = temp_str;
1147   bool saw_control_prefix = false;
1148   size_t format_len = strlen(format_str);
1149
1150   bzero(temp_str, TEMP_STR_SIZE);
1151
1152   for (i=0; i<format_len; i++) {
1153
1154     if (!saw_control_prefix && format_str[i] != '%') {
1155       *tp++ = format_str[i];
1156       saw_control_prefix = false;
1157       continue;
1158     }
1159
1160     switch(format_str[i]) {
1161     case '%':
1162       if (saw_control_prefix) {
1163         *tp++ = '%';
1164       }
1165       saw_control_prefix = !saw_control_prefix;
1166       break;
1167     case 'A':
1168       add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
1169                                               MAX_ALBUM_LEN));
1170       break;
1171
1172     case 'c':
1173       add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
1174       break;
1175
1176     case 'C':
1177       add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
1178       break;
1179
1180     case 'F':
1181       add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
1182       break;
1183
1184     case 'I':
1185       {
1186         switch (itemid->type) {
1187         case VCDINFO_ITEM_TYPE_TRACK:
1188           strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
1189           tp += strlen(_("Track"));
1190         break;
1191         case VCDINFO_ITEM_TYPE_ENTRY:
1192           strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
1193           tp += strlen(_("Entry"));
1194           break;
1195         case VCDINFO_ITEM_TYPE_SEGMENT:
1196           strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
1197           tp += strlen(_("Segment"));
1198           break;
1199         case VCDINFO_ITEM_TYPE_LID:
1200           strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
1201           tp += strlen(_("List ID"));
1202           break;
1203         case VCDINFO_ITEM_TYPE_SPAREID2:
1204           strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
1205           tp += strlen(_("Navigation"));
1206           break;
1207         default:
1208           /* What to do? */
1209           ;
1210         }
1211         saw_control_prefix = false;
1212       }
1213       break;
1214
1215     case 'L':
1216       if (vcdplayer_pbc_is_on(p_vcd)) {
1217         char num_str[40];
1218         sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid);
1219         strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
1220         tp += strlen(num_str);
1221       }
1222       saw_control_prefix = false;
1223       break;
1224
1225     case 'M':
1226       add_format_str_info(mrl);
1227       break;
1228
1229     case 'N':
1230       add_format_num_info(itemid->num, "%d");
1231       break;
1232
1233     case 'p':
1234       add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
1235       break;
1236
1237     case 'P':
1238       add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
1239       break;
1240
1241     case 'S':
1242       if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
1243         char seg_type_str[10];
1244
1245         sprintf(seg_type_str, " %s",
1246                 vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
1247         strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
1248         tp += strlen(seg_type_str);
1249       }
1250       saw_control_prefix = false;
1251       break;
1252
1253     case 'T':
1254       add_format_num_info(p_vcd->cur_track, "%d");
1255       break;
1256
1257     case 'V':
1258       add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
1259       break;
1260
1261     case 'v':
1262       add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
1263       break;
1264
1265     default:
1266       *tp++ = '%';
1267       *tp++ = format_str[i];
1268       saw_control_prefix = false;
1269     }
1270   }
1271   return strdup(temp_str);
1272 }
1273
1274 static void
1275 VCDCreatePlayListItem(const input_thread_t *p_input,
1276                       thread_vcd_data_t *p_vcd,
1277                       playlist_t *p_playlist,
1278                       const vcdinfo_itemid_t *itemid,
1279                       char *psz_mrl, int psz_mrl_max,
1280                       const char *psz_source, int playlist_operation,
1281                       int i_pos)
1282 {
1283   char *p_author;
1284   char *p_title;
1285   char c_type;
1286
1287   switch(itemid->type) {
1288   case VCDINFO_ITEM_TYPE_TRACK:
1289     c_type='T';
1290     break;
1291   case VCDINFO_ITEM_TYPE_SEGMENT:
1292     c_type='S';
1293     break;
1294   case VCDINFO_ITEM_TYPE_LID:
1295     c_type='P';
1296     break;
1297   case VCDINFO_ITEM_TYPE_ENTRY:
1298     c_type='E';
1299     break;
1300   default:
1301     c_type='?';
1302     break;
1303   }
1304
1305   snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
1306            c_type, itemid->num);
1307
1308   p_title =
1309     VCDFormatStr( p_input, p_vcd,
1310                   config_GetPsz( p_input, MODULE_STRING "-title-format" ),
1311                   psz_mrl, itemid );
1312   
1313   playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
1314
1315   p_author =
1316     VCDFormatStr( p_input, p_vcd,
1317                   config_GetPsz( p_input, MODULE_STRING "-author-format" ),
1318                   psz_mrl, itemid );
1319
1320   if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
1321   playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
1322                    p_author);
1323 }
1324
1325 static int
1326 VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1327                   const char *psz_source, vcdinfo_itemid_t *itemid,
1328                   bool play_single_item )
1329 {
1330   unsigned int i;
1331   playlist_t * p_playlist;
1332   char       * psz_mrl;
1333   unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
1334     strlen("@T") + strlen("100") + 1;
1335
1336   psz_mrl = malloc( psz_mrl_max );
1337
1338   if( psz_mrl == NULL )
1339     {
1340       msg_Warn( p_input, "out of memory" );
1341       return -1;
1342     }
1343
1344   p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1345                                                FIND_ANYWHERE );
1346   if( !p_playlist )
1347     {
1348       msg_Warn( p_input, "can't find playlist" );
1349       free(psz_mrl);
1350       return -1;
1351     }
1352
1353   InformationCreate( p_input );
1354
1355   if ( play_single_item ) 
1356     {
1357     /* May fill out more information when the playlist user interface becomes
1358        more mature.
1359      */
1360     VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid,
1361                           psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
1362                           p_playlist->i_index);
1363
1364     } 
1365   else 
1366     {
1367     vcdinfo_itemid_t list_itemid;
1368     list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
1369
1370     playlist_Delete( p_playlist, p_playlist->i_index);
1371
1372     for( i = 0 ; i < p_vcd->num_entries ; i++ )
1373       {
1374         list_itemid.num=i;
1375         VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid,
1376                               psz_mrl, psz_mrl_max, psz_source,
1377                               PLAYLIST_APPEND, PLAYLIST_END);
1378       }
1379
1380     playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
1381
1382   }
1383
1384   vlc_object_release( p_playlist );
1385   free(psz_mrl);
1386   return 0;
1387 }
1388
1389 /*****************************************************************************
1390  * Public routines.
1391  *****************************************************************************/
1392 int
1393 E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
1394                       vlc_value_t oldval, vlc_value_t val, void *p_data )
1395 {
1396   thread_vcd_data_t *p_vcd;
1397
1398   if (NULL == p_vcd_input) return VLC_EGENERIC;
1399
1400   p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1401
1402   if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
1403     msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
1404              p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1405   }
1406   p_vcd->i_debug = val.i_int;
1407   return VLC_SUCCESS;
1408 }
1409
1410 /*****************************************************************************
1411   Open: open VCD.
1412   read in meta-information about VCD: the number of tracks, segments,
1413   entries, size and starting information. Then set up state variables so
1414   that we read/seek starting at the location specified.
1415
1416   On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1417   and VLC_EGENERIC for some other error.
1418  *****************************************************************************/
1419 int
1420 E_(Open) ( vlc_object_t *p_this )
1421 {
1422     input_thread_t *        p_input = (input_thread_t *)p_this;
1423     thread_vcd_data_t *     p_vcd;
1424     char *                  psz_source;
1425     vcdinfo_itemid_t        itemid;
1426     bool                    b_play_ok;
1427     bool                    play_single_item = false;
1428
1429     p_input->pf_read        = VCDRead;
1430     p_input->pf_seek        = VCDSeek;
1431     p_input->pf_set_area    = VCDSetArea;
1432     p_input->pf_set_program = VCDSetProgram;
1433
1434     p_vcd = malloc( sizeof(thread_vcd_data_t) );
1435
1436     if( p_vcd == NULL )
1437     {
1438         LOG_ERR ("out of memory" );
1439         return VLC_ENOMEM;
1440     }
1441
1442     p_input->p_access_data = (void *)p_vcd;
1443     p_vcd->i_debug         = config_GetInt( p_this, MODULE_STRING "-debug" );
1444
1445     /* Set where to log errors messages from libcdio. */
1446     p_vcd_input = (input_thread_t *)p_this;
1447     cdio_log_set_handler ( cdio_log_handler );
1448     vcd_log_set_handler ( vcd_log_handler );
1449
1450     psz_source = VCDParse( p_input, &itemid, &play_single_item );
1451
1452     if ( NULL == psz_source )
1453     {
1454       free( p_vcd );
1455       return( VLC_EGENERIC );
1456     }
1457
1458     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1459                psz_source, p_input->psz_name );
1460
1461     p_vcd->p_segments = NULL;
1462     p_vcd->p_entries  = NULL;
1463
1464     /* set up input  */
1465     p_input->i_mtu = VCD_DATA_ONCE;
1466
1467     vlc_mutex_lock( &p_input->stream.stream_lock );
1468
1469     /* If we are here we can control the pace... */
1470     p_input->stream.b_pace_control = 1;
1471
1472     p_input->stream.b_seekable = 1;
1473     p_input->stream.p_selected_area->i_size = 0;
1474     p_input->stream.p_selected_area->i_tell = 0;
1475
1476     vlc_mutex_unlock( &p_input->stream.stream_lock );
1477
1478     if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1479     {
1480         msg_Warn( p_input, "could not open %s", psz_source );
1481         goto err_exit;
1482     }
1483
1484     p_vcd->b_svd= vcdinfo_get_tracksSVD(p_vcd->vcd);;
1485     
1486     /* Get track information. */
1487     p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
1488                                             vcdinfo_get_cd_image(p_vcd->vcd),
1489                                             &p_vcd->p_sectors );
1490     if( p_vcd->num_tracks < 0 )
1491         LOG_ERR ("unable to count tracks" );
1492     else if( p_vcd->num_tracks <= 1 )
1493         LOG_ERR ("no movie tracks found" );
1494     if( p_vcd->num_tracks <= 1)
1495     {
1496         vcdinfo_close( p_vcd->vcd );
1497         goto err_exit;
1498     }
1499
1500     /* Set stream and area data */
1501     vlc_mutex_lock( &p_input->stream.stream_lock );
1502
1503     /* Initialize ES structures */
1504     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1505
1506     /* disc input method */
1507     p_input->stream.i_method = INPUT_METHOD_VCD;
1508
1509     p_input->stream.i_area_nb = 1;
1510
1511
1512     /* Initialize segment information. */
1513     VCDSegments( p_input );
1514
1515     /* Initialize track area information. */
1516     VCDTracks( p_input );
1517
1518     if( VCDEntryPoints( p_input ) < 0 )
1519     {
1520         msg_Warn( p_input, "could not read entry points, will not use them" );
1521         p_vcd->b_valid_ep = false;
1522     }
1523
1524     if( VCDLIDs( p_input ) < 0 )
1525     {
1526         msg_Warn( p_input, "could not read entry LIDs" );
1527     }
1528
1529     b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1530
1531     vlc_mutex_unlock( &p_input->stream.stream_lock );
1532
1533     if ( ! b_play_ok ) {
1534       vcdinfo_close( p_vcd->vcd );
1535       goto err_exit;
1536     }
1537
1538     if( !p_input->psz_demux || !*p_input->psz_demux )
1539     {
1540 #if FIXED
1541       p_input->psz_demux = "vcdx";
1542 #else
1543       p_input->psz_demux = "ps";
1544 #endif
1545     }
1546
1547     p_vcd->p_intf = intf_Create( p_input, "vcdx" );
1548     p_vcd->p_intf->b_block = VLC_FALSE;
1549     intf_RunThread( p_vcd->p_intf );
1550
1551     if (play_single_item)
1552       VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid, play_single_item );
1553
1554     free( psz_source );
1555
1556     return VLC_SUCCESS;
1557  err_exit:
1558     free( psz_source );
1559     free( p_vcd );
1560     return VLC_EGENERIC;
1561 }
1562
1563 /*****************************************************************************
1564  * Close: closes VCD releasing allocated memory.
1565  *****************************************************************************/
1566 void
1567 E_(Close) ( vlc_object_t *p_this )
1568 {
1569     input_thread_t *   p_input = (input_thread_t *)p_this;
1570     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1571
1572     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1573     vcdinfo_close( p_vcd->vcd );
1574
1575     free( p_vcd->p_entries );
1576     free( p_vcd->p_segments );
1577
1578     /* For reasons that are a mystery to me we don't have to deal with
1579        stopping, and destroying the p_vcd->p_intf thread. And if we do
1580        it causes problems upstream.
1581      */
1582     if( p_vcd->p_intf != NULL )
1583     {
1584         p_vcd->p_intf = NULL;
1585     }
1586
1587     free( p_vcd );
1588     p_input->p_access_data = NULL;
1589     p_vcd_input = NULL;
1590 }