]> git.sesse.net Git - vlc/blob - modules/access/vcdx/access.c
Make sure a couple of variables are initialized before
[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.20 2004/02/22 09:35:48 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_SEGMENT ?
344                         _("Segment"): _("Entry"),
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     uint8_t spare       [4];
967   } vcdsector_t;
968   vcdsector_t vcd_sector;
969
970   if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
971                              &vcd_sector, cur_lsn, true)
972       != 0)
973     {
974       msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
975       return -1;
976     }
977
978   memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
979
980   return( 0 );
981 }
982
983 /****************************************************************************
984  Update the "varname" variable to i_num without triggering a callback.
985 ****************************************************************************/
986 static void
987 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
988               const char *p_varname, char *p_label, 
989               const char *p_debug_label)
990 {
991   vlc_value_t val;
992   val.i_int = i_num;
993   if (NULL != p_vcd_input) {
994     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
995     dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
996   }
997   if (p_label) {
998     vlc_value_t text;
999     text.psz_string = p_label;
1000     var_Change( p_input, p_varname, VLC_VAR_SETTEXT, &text, NULL );
1001   }
1002   var_Change( p_input, p_varname, i_action, &val, NULL );
1003 }
1004
1005
1006 static inline void
1007 MetaInfoAddStr(input_thread_t *p_input, input_info_category_t *p_cat,
1008                playlist_t *p_playlist, char *title,
1009                const char *str)
1010 {
1011   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1012   playlist_item_t *p_item;
1013   if ( str ) {
1014     dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str);
1015     input_AddInfo( p_cat, title, "%s", str );
1016
1017     vlc_mutex_lock( &p_playlist->object_lock );
1018     p_item = playlist_ItemGetByPos( p_playlist, -1 );
1019     vlc_mutex_unlock( &p_playlist->object_lock );
1020
1021     vlc_mutex_lock( &p_item->lock );
1022     playlist_ItemAddInfo( p_item, p_cat->psz_name, title,
1023                           "%s",str );
1024     vlc_mutex_unlock( &p_item->lock );
1025   }
1026 }
1027
1028
1029 static inline void
1030 MetaInfoAddNum(input_thread_t *p_input, input_info_category_t *p_cat,
1031                playlist_t *p_playlist, char *title, int num)
1032 {
1033   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1034   playlist_item_t *p_item;
1035
1036   vlc_mutex_lock( &p_playlist->object_lock );
1037   p_item = playlist_ItemGetByPos( p_playlist, -1 );
1038   vlc_mutex_unlock( &p_playlist->object_lock );
1039
1040   dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num);
1041   input_AddInfo( p_cat, title, "%d", num );
1042
1043   vlc_mutex_lock( &p_item->lock );
1044   playlist_ItemAddInfo( p_item ,  p_cat->psz_name, title, "%d",num );
1045   vlc_mutex_unlock( &p_item->lock );
1046 }
1047
1048 #define addstr(title, str) \
1049   MetaInfoAddStr( p_input, p_cat, p_playlist, title, str );
1050
1051 #define addnum(title, num) \
1052   MetaInfoAddNum( p_input, p_cat, p_playlist, title, num );
1053
1054 static void InformationCreate( input_thread_t *p_input  )
1055 {
1056   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1057   unsigned int i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
1058   unsigned int last_entry = 0;
1059   input_info_category_t *p_cat;
1060   track_t i_track;
1061   playlist_t *p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1062                                                  FIND_PARENT );
1063
1064   p_cat = input_InfoCategory( p_input, "General" );
1065
1066   addstr( _("VCD Format"),  vcdinfo_get_format_version_str(p_vcd->vcd) );
1067   addstr( _("Album"),       vcdinfo_get_album_id(p_vcd->vcd));
1068   addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
1069   addstr( _("Preparer"),    vcdinfo_get_preparer_id(p_vcd->vcd) );
1070   addnum( _("Vol #"),       vcdinfo_get_volume_num(p_vcd->vcd) );
1071   addnum( _("Vol max #"),   vcdinfo_get_volume_count(p_vcd->vcd) );
1072   addstr( _("Volume Set"),  vcdinfo_get_volumeset_id(p_vcd->vcd) );
1073   addstr( _("Volume"),      vcdinfo_get_volume_id(p_vcd->vcd) );
1074   addstr( _("Publisher"),   vcdinfo_get_publisher_id(p_vcd->vcd) );
1075   addstr( _("System Id"),   vcdinfo_get_system_id(p_vcd->vcd) );
1076   addnum( "LIDs",           vcdinfo_get_num_LIDs(p_vcd->vcd) );
1077   addnum( _("Entries"),     vcdinfo_get_num_entries(p_vcd->vcd) );
1078   addnum( _("Segments"),    vcdinfo_get_num_segments(p_vcd->vcd) );
1079   addnum( _("Tracks"),      vcdinfo_get_num_tracks(p_vcd->vcd) );
1080
1081   /* Spit out track information. Could also include MSF info.
1082    */
1083
1084 #define TITLE_MAX 30
1085   for( i_track = 1 ; i_track < p_vcd->num_tracks ; i_track++ ) {
1086     char track_str[TITLE_MAX];
1087     unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd, 
1088                                                            i_track);
1089     snprintf(track_str, TITLE_MAX, "%s%02d", _("Track"), i_track);
1090     p_cat = input_InfoCategory( p_input, track_str );
1091
1092     if (p_vcd->b_svd) {
1093       addnum(_("Audio Channels"),  
1094              vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
1095     }
1096
1097     addnum(_("First Entry Point"), last_entry );
1098     for ( ; last_entry < i_nb 
1099             && vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
1100           last_entry++ ) ;
1101     addnum(_("Last Entry Point"), last_entry-1 );
1102   }
1103 }
1104
1105 #define add_format_str_info(val)                               \
1106   {                                                            \
1107     const char *str = val;                                     \
1108     unsigned int len;                                          \
1109     if (val != NULL) {                                         \
1110       len=strlen(str);                                         \
1111       if (len != 0) {                                          \
1112         strncat(tp, str, TEMP_STR_LEN-(tp-temp_str));          \
1113         tp += len;                                             \
1114       }                                                        \
1115       saw_control_prefix = false;                              \
1116     }                                                          \
1117   }
1118
1119 #define add_format_num_info(val, fmt)                          \
1120   {                                                            \
1121     char num_str[10];                                          \
1122     unsigned int len;                                          \
1123     sprintf(num_str, fmt, val);                                \
1124     len=strlen(num_str);                                       \
1125     if (len != 0) {                                            \
1126       strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));        \
1127       tp += len;                                               \
1128     }                                                          \
1129     saw_control_prefix = false;                                \
1130   }
1131
1132 /*!
1133    Take a format string and expand escape sequences, that is sequences that
1134    begin with %, with information from the current VCD.
1135    The expanded string is returned. Here is a list of escape sequences:
1136
1137    %A : The album information
1138    %C : The VCD volume count - the number of CD's in the collection.
1139    %c : The VCD volume num - the number of the CD in the collection.
1140    %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
1141    %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
1142    %L : The playlist ID prefixed with " LID" if it exists
1143    %M : MRL
1144    %N : The current number of the %I - a decimal number
1145    %P : The publisher ID
1146    %p : The preparer ID
1147    %S : If we are in a segment (menu), the kind of segment
1148    %T : The track number
1149    %V : The volume set ID
1150    %v : The volume ID
1151        A number between 1 and the volume count.
1152    %% : a %
1153 */
1154 static char *
1155 VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1156              const char format_str[], const char *mrl,
1157              const vcdinfo_itemid_t *itemid)
1158 {
1159 #define TEMP_STR_SIZE 256
1160 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
1161   static char    temp_str[TEMP_STR_SIZE];
1162   size_t i;
1163   char * tp = temp_str;
1164   bool saw_control_prefix = false;
1165   size_t format_len = strlen(format_str);
1166
1167   bzero(temp_str, TEMP_STR_SIZE);
1168
1169   for (i=0; i<format_len; i++) {
1170
1171     if (!saw_control_prefix && format_str[i] != '%') {
1172       *tp++ = format_str[i];
1173       saw_control_prefix = false;
1174       continue;
1175     }
1176
1177     switch(format_str[i]) {
1178     case '%':
1179       if (saw_control_prefix) {
1180         *tp++ = '%';
1181       }
1182       saw_control_prefix = !saw_control_prefix;
1183       break;
1184     case 'A':
1185       add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
1186                                               MAX_ALBUM_LEN));
1187       break;
1188
1189     case 'c':
1190       add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
1191       break;
1192
1193     case 'C':
1194       add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
1195       break;
1196
1197     case 'F':
1198       add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
1199       break;
1200
1201     case 'I':
1202       {
1203         switch (itemid->type) {
1204         case VCDINFO_ITEM_TYPE_TRACK:
1205           strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
1206           tp += strlen(_("Track"));
1207         break;
1208         case VCDINFO_ITEM_TYPE_ENTRY:
1209           strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
1210           tp += strlen(_("Entry"));
1211           break;
1212         case VCDINFO_ITEM_TYPE_SEGMENT:
1213           strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
1214           tp += strlen(_("Segment"));
1215           break;
1216         case VCDINFO_ITEM_TYPE_LID:
1217           strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
1218           tp += strlen(_("List ID"));
1219           break;
1220         case VCDINFO_ITEM_TYPE_SPAREID2:
1221           strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
1222           tp += strlen(_("Navigation"));
1223           break;
1224         default:
1225           /* What to do? */
1226           ;
1227         }
1228         saw_control_prefix = false;
1229       }
1230       break;
1231
1232     case 'L':
1233       if (vcdplayer_pbc_is_on(p_vcd)) {
1234         char num_str[40];
1235         sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid);
1236         strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
1237         tp += strlen(num_str);
1238       }
1239       saw_control_prefix = false;
1240       break;
1241
1242     case 'M':
1243       add_format_str_info(mrl);
1244       break;
1245
1246     case 'N':
1247       add_format_num_info(itemid->num, "%d");
1248       break;
1249
1250     case 'p':
1251       add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
1252       break;
1253
1254     case 'P':
1255       add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
1256       break;
1257
1258     case 'S':
1259       if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
1260         char seg_type_str[10];
1261
1262         sprintf(seg_type_str, " %s",
1263                 vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
1264         strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
1265         tp += strlen(seg_type_str);
1266       }
1267       saw_control_prefix = false;
1268       break;
1269
1270     case 'T':
1271       add_format_num_info(p_vcd->cur_track, "%d");
1272       break;
1273
1274     case 'V':
1275       add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
1276       break;
1277
1278     case 'v':
1279       add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
1280       break;
1281
1282     default:
1283       *tp++ = '%';
1284       *tp++ = format_str[i];
1285       saw_control_prefix = false;
1286     }
1287   }
1288   return strdup(temp_str);
1289 }
1290
1291 static void
1292 VCDCreatePlayListItem(const input_thread_t *p_input,
1293                       thread_vcd_data_t *p_vcd,
1294                       playlist_t *p_playlist,
1295                       const vcdinfo_itemid_t *itemid,
1296                       char *psz_mrl, int psz_mrl_max,
1297                       const char *psz_source, int playlist_operation,
1298                       int i_pos)
1299 {
1300   char *p_author;
1301   char *p_title;
1302   char c_type;
1303
1304   switch(itemid->type) {
1305   case VCDINFO_ITEM_TYPE_TRACK:
1306     c_type='T';
1307     break;
1308   case VCDINFO_ITEM_TYPE_SEGMENT:
1309     c_type='S';
1310     break;
1311   case VCDINFO_ITEM_TYPE_LID:
1312     c_type='P';
1313     break;
1314   case VCDINFO_ITEM_TYPE_ENTRY:
1315     c_type='E';
1316     break;
1317   default:
1318     c_type='?';
1319     break;
1320   }
1321
1322   snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
1323            c_type, itemid->num);
1324
1325   p_title =
1326     VCDFormatStr( p_input, p_vcd,
1327                   config_GetPsz( p_input, MODULE_STRING "-title-format" ),
1328                   psz_mrl, itemid );
1329   
1330   playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
1331
1332   p_author =
1333     VCDFormatStr( p_input, p_vcd,
1334                   config_GetPsz( p_input, MODULE_STRING "-author-format" ),
1335                   psz_mrl, itemid );
1336
1337   if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
1338   playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
1339                    p_author);
1340 }
1341
1342 static int
1343 VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1344                   const char *psz_source, vcdinfo_itemid_t *itemid,
1345                   bool play_single_item )
1346 {
1347   unsigned int i;
1348   playlist_t * p_playlist;
1349   char       * psz_mrl;
1350   unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
1351     strlen("@T") + strlen("100") + 1;
1352
1353   psz_mrl = malloc( psz_mrl_max );
1354
1355   if( psz_mrl == NULL )
1356     {
1357       msg_Warn( p_input, "out of memory" );
1358       return -1;
1359     }
1360
1361   p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1362                                                FIND_ANYWHERE );
1363   if( !p_playlist )
1364     {
1365       msg_Warn( p_input, "can't find playlist" );
1366       free(psz_mrl);
1367       return -1;
1368     }
1369
1370   InformationCreate( p_input );
1371
1372   if ( play_single_item ) 
1373     {
1374     /* May fill out more information when the playlist user interface becomes
1375        more mature.
1376      */
1377     VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid,
1378                           psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
1379                           p_playlist->i_index);
1380
1381     } 
1382   else 
1383     {
1384     vcdinfo_itemid_t list_itemid;
1385     list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
1386
1387     playlist_Delete( p_playlist, p_playlist->i_index);
1388
1389     for( i = 0 ; i < p_vcd->num_entries ; i++ )
1390       {
1391         list_itemid.num=i;
1392         VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid,
1393                               psz_mrl, psz_mrl_max, psz_source,
1394                               PLAYLIST_APPEND, PLAYLIST_END);
1395       }
1396
1397     playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
1398
1399   }
1400
1401   vlc_object_release( p_playlist );
1402   free(psz_mrl);
1403   return 0;
1404 }
1405
1406 /*****************************************************************************
1407  * Public routines.
1408  *****************************************************************************/
1409 int
1410 E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
1411                       vlc_value_t oldval, vlc_value_t val, void *p_data )
1412 {
1413   thread_vcd_data_t *p_vcd;
1414
1415   if (NULL == p_vcd_input) return VLC_EGENERIC;
1416
1417   p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1418
1419   if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
1420     msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
1421              p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1422   }
1423   p_vcd->i_debug = val.i_int;
1424   return VLC_SUCCESS;
1425 }
1426
1427 /*****************************************************************************
1428   Open: open VCD.
1429   read in meta-information about VCD: the number of tracks, segments,
1430   entries, size and starting information. Then set up state variables so
1431   that we read/seek starting at the location specified.
1432
1433   On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1434   and VLC_EGENERIC for some other error.
1435  *****************************************************************************/
1436 int
1437 E_(Open) ( vlc_object_t *p_this )
1438 {
1439     input_thread_t *        p_input = (input_thread_t *)p_this;
1440     thread_vcd_data_t *     p_vcd;
1441     char *                  psz_source;
1442     vcdinfo_itemid_t        itemid;
1443     bool                    b_play_ok;
1444     bool                    play_single_item = false;
1445
1446     p_input->pf_read        = VCDRead;
1447     p_input->pf_seek        = VCDSeek;
1448     p_input->pf_set_area    = VCDSetArea;
1449     p_input->pf_set_program = VCDSetProgram;
1450
1451     p_vcd = malloc( sizeof(thread_vcd_data_t) );
1452
1453     if( p_vcd == NULL )
1454     {
1455         LOG_ERR ("out of memory" );
1456         return VLC_ENOMEM;
1457     }
1458
1459     p_input->p_access_data = (void *)p_vcd;
1460     p_vcd->i_debug         = config_GetInt( p_this, MODULE_STRING "-debug" );
1461     p_vcd->in_still        = false;
1462     p_vcd->play_item.type  = VCDINFO_ITEM_TYPE_NOTFOUND;
1463
1464     /* Set where to log errors messages from libcdio. */
1465     p_vcd_input = (input_thread_t *)p_this;
1466     cdio_log_set_handler ( cdio_log_handler );
1467     vcd_log_set_handler ( vcd_log_handler );
1468
1469     psz_source = VCDParse( p_input, &itemid, &play_single_item );
1470
1471     if ( NULL == psz_source )
1472     {
1473       free( p_vcd );
1474       return( VLC_EGENERIC );
1475     }
1476
1477     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1478                psz_source, p_input->psz_name );
1479
1480     p_vcd->p_segments = NULL;
1481     p_vcd->p_entries  = NULL;
1482
1483     /* set up input  */
1484     p_input->i_mtu = VCD_DATA_ONCE;
1485
1486     vlc_mutex_lock( &p_input->stream.stream_lock );
1487
1488     /* If we are here we can control the pace... */
1489     p_input->stream.b_pace_control = 1;
1490
1491     p_input->stream.b_seekable = 1;
1492     p_input->stream.p_selected_area->i_size = 0;
1493     p_input->stream.p_selected_area->i_tell = 0;
1494
1495     vlc_mutex_unlock( &p_input->stream.stream_lock );
1496
1497     if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1498     {
1499         msg_Warn( p_input, "could not open %s", psz_source );
1500         goto err_exit;
1501     }
1502
1503     p_vcd->b_svd= vcdinfo_get_tracksSVD(p_vcd->vcd);;
1504     
1505     /* Get track information. */
1506     p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
1507                                             vcdinfo_get_cd_image(p_vcd->vcd),
1508                                             &p_vcd->p_sectors );
1509     if( p_vcd->num_tracks < 0 )
1510         LOG_ERR ("unable to count tracks" );
1511     else if( p_vcd->num_tracks <= 1 )
1512         LOG_ERR ("no movie tracks found" );
1513     if( p_vcd->num_tracks <= 1)
1514     {
1515         vcdinfo_close( p_vcd->vcd );
1516         goto err_exit;
1517     }
1518
1519     /* Set stream and area data */
1520     vlc_mutex_lock( &p_input->stream.stream_lock );
1521
1522     /* Initialize ES structures */
1523     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1524
1525     /* disc input method */
1526     p_input->stream.i_method = INPUT_METHOD_VCD;
1527
1528     p_input->stream.i_area_nb = 1;
1529
1530
1531     /* Initialize segment information. */
1532     VCDSegments( p_input );
1533
1534     /* Initialize track area information. */
1535     VCDTracks( p_input );
1536
1537     if( VCDEntryPoints( p_input ) < 0 )
1538     {
1539         msg_Warn( p_input, "could not read entry points, will not use them" );
1540         p_vcd->b_valid_ep = false;
1541     }
1542
1543     if( VCDLIDs( p_input ) < 0 )
1544     {
1545         msg_Warn( p_input, "could not read entry LIDs" );
1546     }
1547
1548     b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1549
1550     vlc_mutex_unlock( &p_input->stream.stream_lock );
1551
1552     if ( ! b_play_ok ) {
1553       vcdinfo_close( p_vcd->vcd );
1554       goto err_exit;
1555     }
1556
1557     if( !p_input->psz_demux || !*p_input->psz_demux )
1558     {
1559 #if FIXED
1560       p_input->psz_demux = "vcdx";
1561 #else
1562       p_input->psz_demux = "ps";
1563 #endif
1564     }
1565
1566     p_vcd->p_intf = intf_Create( p_input, "vcdx" );
1567     p_vcd->p_intf->b_block = VLC_FALSE;
1568     intf_RunThread( p_vcd->p_intf );
1569
1570     if (play_single_item)
1571       VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid, play_single_item );
1572
1573     free( psz_source );
1574
1575     return VLC_SUCCESS;
1576  err_exit:
1577     free( psz_source );
1578     free( p_vcd );
1579     return VLC_EGENERIC;
1580 }
1581
1582 /*****************************************************************************
1583  * Close: closes VCD releasing allocated memory.
1584  *****************************************************************************/
1585 void
1586 E_(Close) ( vlc_object_t *p_this )
1587 {
1588     input_thread_t *   p_input = (input_thread_t *)p_this;
1589     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1590
1591     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1592     vcdinfo_close( p_vcd->vcd );
1593
1594     free( p_vcd->p_entries );
1595     free( p_vcd->p_segments );
1596
1597     /* For reasons that are a mystery to me we don't have to deal with
1598        stopping, and destroying the p_vcd->p_intf thread. And if we do
1599        it causes problems upstream.
1600      */
1601     if( p_vcd->p_intf != NULL )
1602     {
1603         p_vcd->p_intf = NULL;
1604     }
1605
1606     free( p_vcd );
1607     p_input->p_access_data = NULL;
1608     p_vcd_input = NULL;
1609 }