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