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