]> git.sesse.net Git - vlc/blob - modules/access/vcdx/access.c
Minor name-change tidying up.
[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 VideoLAN
7  * $Id: access.c,v 1.5 2003/11/26 01:28:52 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_interface.h>
34
35 #include "../../demux/mpeg/system.h"
36 #include "vcd.h"
37 #include "intf.h"
38 #include "vcdplayer.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 /*****************************************************************************
54  * Local prototypes
55  *****************************************************************************/
56
57 /* First those which are accessed from outside (via pointers). */
58 static int  VCDRead         ( input_thread_t *, byte_t *, size_t );
59 static int  VCDSetProgram   ( input_thread_t *, pgrm_descriptor_t * );
60
61 /* Now those which are strictly internal */
62 static void VCDSetOrigin    ( input_thread_t *, lsn_t origin_lsn, 
63                               lsn_t cur_lsn, lsn_t end_lsn, 
64                               int cur_entry, track_t track );
65 static int  VCDEntryPoints  ( input_thread_t * );
66 static int  VCDLIDs         ( input_thread_t * );
67 static int  VCDSegments     ( input_thread_t * );
68 static void VCDTracks       ( input_thread_t * );
69 static int  VCDReadSector   ( vlc_object_t *p_this, 
70                               const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn, 
71                               byte_t * p_buffer );
72 static char *VCDParse       ( input_thread_t *, 
73                               /*out*/ vcdinfo_itemid_t * p_itemid );
74
75 static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
76                           const char *varname, const char *label );
77
78 static vcdinfo_obj_t *vcd_Open   ( vlc_object_t *p_this, const char *psz_dev );
79
80 /****************************************************************************
81  * Private functions
82  ****************************************************************************/
83
84 /* FIXME: This variable is a hack. Would be nice to eliminate the 
85    global-ness. */
86
87 static input_thread_t *p_vcd_input = NULL;
88
89 int
90 E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
91                       vlc_value_t oldval, vlc_value_t val, void *p_data )
92 {
93   thread_vcd_data_t *p_vcd;
94
95   if (NULL == p_vcd_input) return VLC_EGENERIC;
96   
97   p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
98
99   if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
100     msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d", 
101              p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
102   }
103   p_vcd->i_debug = val.i_int;
104   return VLC_SUCCESS;
105 }
106
107 /* process messages that originate from libcdio. */
108 static void
109 cdio_log_handler (cdio_log_level_t level, const char message[])
110 {
111   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
112   switch (level) {
113   case CDIO_LOG_DEBUG:
114   case CDIO_LOG_INFO:
115     if (p_vcd->i_debug & INPUT_DBG_CDIO) 
116       msg_Dbg( p_vcd_input, message);
117     break;
118   case CDIO_LOG_WARN:
119     msg_Warn( p_vcd_input, message);
120     break;
121   case CDIO_LOG_ERROR:
122   case CDIO_LOG_ASSERT:
123     msg_Err( p_vcd_input, message);
124     break;
125   default:
126     msg_Warn( p_vcd_input, message,
127             _("The above message had unknown vcdimager log level"), 
128             level);
129   }
130   return;
131 }
132
133 /* process messages that originate from vcdinfo. */
134 static void
135 vcd_log_handler (vcd_log_level_t level, const char message[])
136 {
137   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
138   switch (level) {
139   case VCD_LOG_DEBUG:
140   case VCD_LOG_INFO:
141     if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
142       msg_Dbg( p_vcd_input, message);
143     break;
144   case VCD_LOG_WARN:
145     msg_Warn( p_vcd_input, message);
146     break;
147   case VCD_LOG_ERROR:
148   case VCD_LOG_ASSERT:
149     msg_Err( p_vcd_input, message);
150     break;
151   default:
152     msg_Warn( p_vcd_input, "%s\n%s %d", message,
153             _("The above message had unknown vcdimager log level"), 
154             level);
155   }
156   return;
157 }
158
159 /*
160  * Data reading functions
161  */
162
163 /*****************************************************************************
164   Open: open VCD.
165   read in meta-information about VCD: the number of tracks, segments, 
166   entries, size and starting information. Then set up state variables so
167   that we read/seek starting at the location specified.
168
169   On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM, 
170   and VLC_EGENERIC for some other error.
171  *****************************************************************************/
172 int 
173 E_(Open) ( vlc_object_t *p_this )
174 {
175     input_thread_t *        p_input = (input_thread_t *)p_this;
176     thread_vcd_data_t *     p_vcd;
177     char *                  psz_source;
178     vcdinfo_itemid_t        itemid;
179     bool                    b_play_ok;
180     
181     p_input->pf_read        = VCDRead;
182     p_input->pf_seek        = VCDSeek;
183     p_input->pf_set_area    = VCDSetArea;
184     p_input->pf_set_program = VCDSetProgram;
185
186     p_vcd = malloc( sizeof(thread_vcd_data_t) );
187
188     if( p_vcd == NULL )
189     {
190         LOG_ERR ("out of memory" );
191         return VLC_ENOMEM;
192     }
193
194     p_input->p_access_data = (void *)p_vcd;
195     p_vcd->i_debug         = config_GetInt( p_this, MODULE_STRING "-debug" );
196     psz_source             = VCDParse( p_input, &itemid );
197
198     if ( NULL == psz_source ) 
199     {
200       free( p_vcd );
201       return( VLC_EGENERIC );
202     }
203
204     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
205
206     p_vcd->p_segments = NULL;
207     p_vcd->p_entries  = NULL;
208     
209     /* set up input  */
210     p_input->i_mtu = VCD_DATA_ONCE;
211
212     vlc_mutex_lock( &p_input->stream.stream_lock );
213
214     /* If we are here we can control the pace... */
215     p_input->stream.b_pace_control = 1;
216
217     p_input->stream.b_seekable = 1;
218     p_input->stream.p_selected_area->i_size = 0;
219     p_input->stream.p_selected_area->i_tell = 0;
220
221     vlc_mutex_unlock( &p_input->stream.stream_lock );
222
223     if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
224     {
225         msg_Warn( p_input, "could not open %s", psz_source );
226         free( psz_source );
227         free( p_vcd );
228         return VLC_EGENERIC;
229     }
230
231     /* Get track information. */
232     p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
233                                             vcdinfo_get_cd_image(p_vcd->vcd), 
234                                             &p_vcd->p_sectors );
235     free( psz_source );
236     if( p_vcd->num_tracks < 0 )
237         LOG_ERR ("unable to count tracks" );
238     else if( p_vcd->num_tracks <= 1 )
239         LOG_ERR ("no movie tracks found" );
240     if( p_vcd->num_tracks <= 1)
241     {
242         vcdinfo_close( p_vcd->vcd );
243         free( p_vcd );
244         return VLC_EGENERIC;
245     }
246
247     /* Set stream and area data */
248     vlc_mutex_lock( &p_input->stream.stream_lock );
249
250     /* Initialize ES structures */
251     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
252
253     /* disc input method */
254     p_input->stream.i_method = INPUT_METHOD_VCD;
255
256     p_input->stream.i_area_nb = 1;
257     
258
259     /* Initialize segment information. */
260     VCDSegments( p_input );
261     
262     /* Initialize track area information. */
263     VCDTracks( p_input );
264     
265     if( VCDEntryPoints( p_input ) < 0 )
266     {
267         msg_Warn( p_input, "could not read entry points, will not use them" );
268         p_vcd->b_valid_ep = false;
269     }
270
271     if( VCDLIDs( p_input ) < 0 )
272     {
273         msg_Warn( p_input, "could not read entry LIDs" );
274     }
275
276     b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
277     
278     vlc_mutex_unlock( &p_input->stream.stream_lock );
279
280     if ( ! b_play_ok ) {
281       vcdinfo_close( p_vcd->vcd );
282       free( p_vcd );
283       return VLC_EGENERIC;
284     }
285
286     if( !p_input->psz_demux || !*p_input->psz_demux )
287     {
288 #if FIXED
289       p_input->psz_demux = "vcdx";
290 #else
291       p_input->psz_demux = "ps";
292 #endif
293     }
294
295     p_vcd->p_intf = intf_Create( p_input, "vcdx" );
296     p_vcd->p_intf->b_block = VLC_FALSE;
297     intf_RunThread( p_vcd->p_intf );
298
299     return VLC_SUCCESS;
300 }
301
302 /*****************************************************************************
303  * Close: closes VCD releasing allocated memory.
304  *****************************************************************************/
305 void 
306 E_(Close) ( vlc_object_t *p_this )
307 {
308     input_thread_t *   p_input = (input_thread_t *)p_this;
309     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
310
311     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
312     vcdinfo_close( p_vcd->vcd );
313
314     free( p_vcd->p_entries );
315     free( p_vcd->p_segments );
316
317     /* For reasons that are a mystery to me we don't have to deal with
318        stopping, and destroying the p_vcd->p_intf thread. And if we do
319        it causes problems upstream.
320      */
321     if( p_vcd->p_intf != NULL )
322     {
323         p_vcd->p_intf = NULL;
324     }
325
326     free( p_vcd );
327     p_input->p_access_data = NULL;
328     p_vcd_input = NULL;
329 }
330
331 /*****************************************************************************
332  * VCDRead: reads i_len bytes from the VCD into p_buffer.
333  *****************************************************************************
334  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
335  * bytes.
336  *****************************************************************************/
337 static int 
338 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
339 {
340     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
341     int                     i_blocks;
342     int                     i_index;
343     int                     i_read;
344     byte_t                  p_last_sector[ M2F2_SECTOR_SIZE ];
345
346     i_read = 0;
347
348     dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn );
349
350     /* Compute the number of blocks we have to read */
351
352     i_blocks = i_len / M2F2_SECTOR_SIZE;
353
354     for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
355     {
356
357       if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
358         vcdplayer_read_status_t read_status;
359
360         /* We've run off of the end of this entry. Do we continue or stop? */
361         dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), 
362                    "end reached, cur: %u", p_vcd->cur_lsn );
363
364         read_status = vcdplayer_pbc_is_on( p_vcd ) 
365           ? vcdplayer_pbc_nav( p_input ) 
366           : vcdplayer_non_pbc_nav( p_input );
367
368         switch (read_status) {
369         case READ_END:
370           /* End reached. Return NULL to indicated this. */
371         case READ_ERROR:
372           /* Some sort of error. */
373           return i_read;
374
375         case READ_STILL_FRAME: 
376           {
377             /* Reached the end of a still frame. */
378
379             byte_t * p_buf = p_buffer;
380             pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
381
382             p_buf += (i_index*M2F2_SECTOR_SIZE);
383             memset(p_buf, 0, M2F2_SECTOR_SIZE);
384             p_buf += 2;
385             *p_buf = 0x01;
386             dbg_print(INPUT_DBG_STILL, "Handled still event\n");
387
388             /* p_vcd->p_intf->b_end_of_cell = true; */
389             input_SetStatus( p_input, INPUT_STATUS_PAUSE );
390
391             vlc_mutex_lock( &p_input->stream.stream_lock );
392
393             p_pgrm = p_input->stream.p_selected_program;
394             p_pgrm->i_synchro_state = SYNCHRO_REINIT;
395
396             vlc_mutex_unlock( &p_input->stream.stream_lock );
397
398             input_ClockManageControl( p_input, p_pgrm, 0 );
399
400             return i_read + M2F2_SECTOR_SIZE;
401           }
402         default:
403         case READ_BLOCK:
404           break;
405         }
406       }
407
408       if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
409                           p_vcd->cur_lsn, 
410                           p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
411         {
412           LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
413           return -1;
414         }
415       
416       p_vcd->cur_lsn ++;
417       
418       /* Update chapter */
419       if( p_vcd->b_valid_ep &&
420           /* FIXME kludge so that read does not update chapter
421            * when a manual chapter change was requested and not
422            * yet accomplished */
423           !p_input->stream.p_new_area )
424         {
425           unsigned int i_entry = p_input->stream.p_selected_area->i_part;
426           
427           vlc_mutex_lock( &p_input->stream.stream_lock );
428           
429           if( i_entry < p_vcd->num_entries &&
430               p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
431             {
432               dbg_print( INPUT_DBG_PBC, 
433                          "new entry, i_entry %d, sector %d, es %d",
434                          i_entry, p_vcd->cur_lsn, 
435                          p_vcd->p_entries[i_entry] );
436               p_vcd->play_item.num = 
437                 ++ p_input->stream.p_selected_area->i_part;
438               p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
439               VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
440                             "chapter", "Setting entry" );
441             }
442           vlc_mutex_unlock( &p_input->stream.stream_lock );
443         }
444
445         i_read += M2F2_SECTOR_SIZE;
446     }
447
448     if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
449     {
450         if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
451                             p_vcd->cur_lsn, p_last_sector ) < 0 )
452         {
453             LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
454             return -1;
455         }
456
457         p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
458                                    p_last_sector, i_len % M2F2_SECTOR_SIZE );
459         i_read += i_len % M2F2_SECTOR_SIZE;
460     }
461
462     return i_read;
463 }
464
465
466 /*****************************************************************************
467  * VCDSetProgram: Does nothing since a VCD is mono_program
468  *****************************************************************************/
469 static int 
470 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
471 {
472     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
473     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
474     return 0;
475 }
476
477
478 /*****************************************************************************
479  * VCDSetArea: initialize internal data structures and input stream data 
480    so set subsequent reading and seeking to reflect that we are
481    at track x, entry or segment y.
482    This is called for each user navigation request, e.g. the GUI 
483    Chapter/Title selections or in initial MRL parsing. 
484  ****************************************************************************/
485 int 
486 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
487 {
488     thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
489     unsigned int i_entry = p_area->i_part;
490     track_t i_track      = p_area->i_id;
491     int old_seekable     = p_input->stream.b_seekable;
492     unsigned int i_nb    = p_area->i_plugin_data + p_area->i_part_nb;
493
494     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
495                "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
496                i_track, i_entry, old_seekable, 
497                (long unsigned int) p_area, 
498                (long unsigned int) p_input->stream.p_selected_area );
499
500     /* we can't use the interface slider until initilization is complete */
501     p_input->stream.b_seekable = 0;
502
503     if( p_area != p_input->stream.p_selected_area )
504     {
505         unsigned int i;
506
507         /* If is the result of a track change, make the entry valid. */
508         if (i_entry < p_area->i_plugin_data || i_entry >= i_nb) 
509           i_entry = p_area->i_plugin_data;
510
511         /* Change the default area */
512         p_input->stream.p_selected_area = p_area;
513
514         /* Update the navigation variables without triggering a callback */
515         VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title", 
516                       "Setting track");
517
518         var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
519         for( i = p_area->i_plugin_data; i < i_nb; i++ )
520         {
521           VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, 
522                         "chapter",  "Adding entry choice");
523         }
524     }
525
526     if (i_track == 0) 
527       VCDSetOrigin( p_input, p_vcd->p_segments[i_entry], 
528                     p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
529                     i_entry, 0 );
530     else
531       VCDSetOrigin( p_input, p_vcd->p_sectors[i_track], 
532                     vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry), 
533                     p_vcd->p_sectors[i_track+1],
534                     i_entry, i_track );
535
536     p_input->stream.b_seekable = old_seekable;
537     /* warn interface that something has changed */
538     p_input->stream.b_changed = 1;
539
540     return VLC_SUCCESS;
541 }
542
543
544 /****************************************************************************
545  * VCDSeek
546  ****************************************************************************/
547 void 
548 VCDSeek( input_thread_t * p_input, off_t i_off )
549 {
550     thread_vcd_data_t * p_vcd;
551     unsigned int i_entry=0; /* invalid entry */
552
553     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
554
555     p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
556
557     vlc_mutex_lock( &p_input->stream.stream_lock );
558 #define p_area p_input->stream.p_selected_area
559     /* Find entry */
560     if( p_vcd->b_valid_ep )
561     {
562         for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
563         {
564             if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
565             {
566               VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE, 
567                             "chapter", "Setting entry" );
568               break;
569             }
570         }
571         p_vcd->play_item.num  = p_area->i_part = i_entry;
572         p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
573     }
574 #undef p_area
575
576     p_input->stream.p_selected_area->i_tell = i_off;
577
578     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
579     "orig %d, cur: %d, offset: %lld, start: %lld, entry %d", 
580                p_vcd->origin_lsn, p_vcd->cur_lsn, i_off, 
581                p_input->stream.p_selected_area->i_start, i_entry );
582
583     vlc_mutex_unlock( &p_input->stream.stream_lock );
584 }
585
586 /*****************************************************************************
587   VCDPlay: set up internal structures so seeking/reading places an item.
588   itemid: the thing to play.
589   user_entry: true if itemid is a user selection (rather than internally-
590   generated selection such as via PBC) in which case we may have to adjust 
591   for differences in numbering. 
592  *****************************************************************************/
593 int
594 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
595 {
596     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
597     input_area_t *          p_area;
598     
599     p_vcd->in_still = 0;
600
601     dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n", 
602               itemid.num, itemid.type);
603
604 #define area p_input->stream.pp_areas
605
606     switch (itemid.type) {
607     case VCDINFO_ITEM_TYPE_TRACK:
608
609       /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
610        */
611
612       if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
613         LOG_ERR ("Invalid track number %d", itemid.num );
614         return VLC_EGENERIC;
615       }
616       p_area           = area[itemid.num];
617       p_area->i_part   = p_area->i_plugin_data;
618       p_input->stream.b_seekable = 1;
619       break;
620     case VCDINFO_ITEM_TYPE_SEGMENT: 
621       /* Valid segments go from 0...num_segments-1. */
622       if (itemid.num >= p_vcd->num_segments) {
623         LOG_ERR ( "Invalid segment number: %d", itemid.num );
624         return VLC_EGENERIC;
625       } else {
626         vcdinfo_video_segment_type_t segtype = 
627           vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
628         
629         dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d", 
630                   vcdinfo_video_type2str(p_vcd->vcd, itemid.num), 
631                   (int) segtype, itemid.num);
632         
633         p_area           = area[0];
634         p_area->i_part   = itemid.num;
635         
636         switch (segtype)
637           {
638           case VCDINFO_FILES_VIDEO_NTSC_STILL:
639           case VCDINFO_FILES_VIDEO_NTSC_STILL2:
640           case VCDINFO_FILES_VIDEO_PAL_STILL:
641           case VCDINFO_FILES_VIDEO_PAL_STILL2:
642             p_input->stream.b_seekable = 0;
643             p_vcd->in_still = -5;
644             break;
645           default:
646             p_input->stream.b_seekable = 1;
647             p_vcd->in_still = 0;
648           }
649       }
650       break;
651       
652     case VCDINFO_ITEM_TYPE_LID:
653       /* LIDs go from 1..num_lids. */
654       if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
655         LOG_ERR ( "Invalid LID number: %d", itemid.num );
656         return VLC_EGENERIC;
657       } else {
658         p_vcd->cur_lid = itemid.num;
659         vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
660     
661         switch (p_vcd->pxd.descriptor_type) {
662       
663         case PSD_TYPE_SELECTION_LIST:
664         case PSD_TYPE_EXT_SELECTION_LIST: {
665           vcdinfo_itemid_t trans_itemid;
666           uint16_t trans_itemid_num;
667           
668           if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
669           trans_itemid_num  = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
670           vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
671           p_vcd->loop_count = 1;
672           p_vcd->loop_item  = trans_itemid;
673           return VCDPlay( p_input, trans_itemid );
674           break;
675         }
676           
677         case PSD_TYPE_PLAY_LIST: {
678           if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
679           p_vcd->pdi = -1;
680           return vcdplayer_inc_play_item(p_input) 
681             ? VLC_SUCCESS : VLC_EGENERIC;
682           break;
683         }
684           
685         case PSD_TYPE_END_LIST:
686         case PSD_TYPE_COMMAND_LIST:
687           
688         default:
689           ;
690         }
691       }
692       return VLC_EGENERIC;
693     case VCDINFO_ITEM_TYPE_ENTRY:
694       /* Entries go from 0..num_entries-1. */
695       if (itemid.num >= p_vcd->num_entries) {
696         LOG_ERR ("Invalid entry number: %d", itemid.num );
697         return VLC_EGENERIC;
698       } else {
699         track_t cur_track  = vcdinfo_get_track(p_vcd->vcd,  itemid.num);
700         p_area             = area[cur_track];
701         p_area->i_part     = itemid.num;
702         p_input->stream.b_seekable = 1;
703       }
704       break;
705     default:
706       LOG_ERR ("unknown entry type" );
707       return VLC_EGENERIC;
708     }
709
710     VCDSetArea( p_input, p_area );
711
712 #undef area
713
714     p_vcd->play_item = itemid;
715
716     dbg_print( (INPUT_DBG_CALL), 
717                "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d", 
718                p_area->i_start, p_area->i_size, 
719                p_area->i_tell, p_vcd->cur_lsn );
720         
721     return VLC_SUCCESS;
722 }
723
724 /*****************************************************************************
725   VCDEntryPoints: Reads the information about the entry points on the disc
726   and initializes area information with that.
727   Before calling this track information should have been read in.
728  *****************************************************************************/
729 static int 
730 VCDEntryPoints( input_thread_t * p_input )
731 {
732     thread_vcd_data_t *               p_vcd;
733     unsigned int                      i_nb;
734     unsigned int                      i, i_entry_index = 0;
735     unsigned int                      i_previous_track = CDIO_INVALID_TRACK;
736
737     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
738
739     i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
740     if (0 == i_nb) 
741       return -1;
742     
743     p_vcd->p_entries  = malloc( sizeof( lba_t ) * i_nb );
744
745     if( p_vcd->p_entries == NULL )
746     {
747         LOG_ERR ("not enough memory for entry points treatment" );
748         return -1;
749     }
750
751     p_vcd->num_entries = 0;
752
753     for( i = 0 ; i < i_nb ; i++ )
754     {
755         track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
756         if( i_track <= p_input->stream.i_area_nb )
757         {
758             p_vcd->p_entries[i] = 
759               vcdinfo_get_entry_lsn(p_vcd->vcd, i);
760             p_input->stream.pp_areas[i_track]->i_part_nb ++;
761
762             /* if this entry belongs to a new track */
763             if( i_track != i_previous_track )
764             {
765                 /* i_plugin_data is used to store the first entry of the area*/
766                 p_input->stream.pp_areas[i_track]->i_plugin_data =
767                                                             i_entry_index;
768                 i_previous_track = i_track;
769                 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
770             }
771             i_entry_index ++;
772             p_vcd->num_entries ++;
773         }
774         else
775             msg_Warn( p_input, "wrong track number found in entry points" );
776     }
777     p_vcd->b_valid_ep = true;
778     return 0;
779 }
780
781 /*****************************************************************************
782  * VCDSegments: Reads the information about the segments the disc.
783  *****************************************************************************/
784 static int
785 VCDSegments( input_thread_t * p_input )
786 {
787     thread_vcd_data_t * p_vcd;
788     unsigned int        i;
789     unsigned int        num_segments;
790     
791
792     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
793     num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
794
795 #define area p_input->stream.pp_areas
796
797     /* area 0 is reserved for segments. Set Absolute start offset
798          and size */
799     area[0]->i_plugin_data = 0;
800     input_DelArea( p_input, area[0] );
801     input_AddArea( p_input, 0, 0 );
802     
803     area[0]->i_start = (off_t)p_vcd->p_sectors[0] 
804       * (off_t)M2F2_SECTOR_SIZE;
805     area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
806       * (off_t)M2F2_SECTOR_SIZE;
807     
808     /* Default Segment  */
809     area[0]->i_part = 0;
810     
811     /* i_plugin_data is used to store which entry point is the first
812        of the track (area) */
813     area[0]->i_plugin_data = 0;
814
815     area[0]->i_part_nb = 0;
816     
817     dbg_print( INPUT_DBG_MRL, 
818                "area[0] id: %d, i_start: %lld, i_size: %lld", 
819                area[0]->i_id, area[0]->i_start, area[0]->i_size );
820
821     if (num_segments == 0) return 0;
822
823     /* We have one additional segment allocated so we can get the size
824        by subtracting seg[i+1] - seg[i].
825      */
826     p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
827     if( p_vcd->p_segments == NULL )
828     {
829         LOG_ERR ("not enough memory for segment treatment" );
830         return -1;
831     }
832
833     /* Update the navigation variables without triggering a callback */
834     VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
835     var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
836     
837     for( i = 0 ; i < num_segments ; i++ )
838     {
839       p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
840       area[0]->i_part_nb ++;
841       VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, 
842                     "chapter", "Adding segment choice");
843     }
844
845 #undef area
846
847     p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
848       vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
849     
850     return 0;
851 }
852
853 /*****************************************************************************
854  VCDTracks: initializes area information. 
855  Before calling this track information should have been read in.
856  *****************************************************************************/
857 static void
858 VCDTracks( input_thread_t * p_input )
859 {
860     thread_vcd_data_t * p_vcd;
861     unsigned int        i;
862
863     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
864
865 #define area p_input->stream.pp_areas
866
867     /* We start area addressing for tracks at 1 since the default area 0
868        is reserved for segments */
869
870     for( i = 1 ; i < p_vcd->num_tracks ; i++ )
871     {
872         /* Tracks are Program Chains */
873         input_AddArea( p_input, i, i );
874
875         /* Absolute start byte offset and byte size */
876         area[i]->i_start = (off_t) p_vcd->p_sectors[i] 
877                            * (off_t)M2F2_SECTOR_SIZE;
878         area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
879                            * (off_t)M2F2_SECTOR_SIZE;
880
881         /* Current entry being played in track */
882         area[i]->i_part = 0;
883
884         /* i_plugin_data is used to store which entry point is the first
885          * of the track (area) */
886         area[i]->i_plugin_data = 0;
887
888         dbg_print( INPUT_DBG_MRL, 
889                    "area[%d] id: %d, i_start: %lld, i_size: %lld", 
890                    i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
891     }
892
893 #undef area
894
895     return ;
896 }
897
898 /*****************************************************************************
899   VCDLIDs: Reads the LIST IDs from the LOT.
900  *****************************************************************************/
901 static int 
902 VCDLIDs( input_thread_t * p_input )
903 {
904     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
905
906     p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
907     p_vcd->cur_lid  = VCDINFO_INVALID_ENTRY;
908
909     if (vcdinfo_read_psd (p_vcd->vcd)) {
910       
911       vcdinfo_visit_lot (p_vcd->vcd, false);
912       
913 #if FIXED
914     /* 
915        We need to change libvcdinfo to be more robust when there are 
916        problems reading the extended PSD. Given that area-highlighting and 
917        selection features in the extended PSD haven't been implemented,
918        it's best then to not try to read this at all.
919      */
920       if (vcdinfo_get_psd_x_size(p_vcd->vcd))
921         vcdinfo_visit_lot (p_vcd->vcd, true);
922 #endif 
923     }
924
925     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), 
926                "num LIDs=%d", p_vcd->num_lids);
927
928     return 0;
929 }
930
931 /*****************************************************************************
932  * VCDParse: parse command line
933  *****************************************************************************/
934 static char * 
935 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
936 {
937     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
938     char *             psz_parser;
939     char *             psz_source;
940     char *             psz_next;
941
942     if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
943       p_itemid->type=VCDINFO_ITEM_TYPE_LID;
944       p_itemid->num=1;
945     } else {
946       p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
947       p_itemid->num=1;
948     }
949     
950 #ifdef WIN32
951     /* On Win32 we want the VCD access plugin to be explicitly requested,
952      * we end up with lots of problems otherwise */
953     if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
954 #endif
955
956     if( !p_input->psz_name )
957     {
958         return NULL;
959     }
960
961     psz_parser = psz_source = strdup( p_input->psz_name );
962
963     /* Parse input string :
964      * [device][@[type][title]] */
965     while( *psz_parser && *psz_parser != '@' )
966     {
967         psz_parser++;
968     }
969
970     if( *psz_parser == '@' )
971     {
972       /* Found the divide between the source name and the 
973          type+entry number. */
974       unsigned int num;
975       
976       *psz_parser = '\0';
977       ++psz_parser;
978       if( *psz_parser )
979         {
980           switch(*psz_parser) {
981           case 'E': 
982             p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
983             ++psz_parser;
984             break;
985           case 'P': 
986             p_itemid->type = VCDINFO_ITEM_TYPE_LID;
987             ++psz_parser;
988             break;
989           case 'S': 
990             p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
991             ++psz_parser;
992             break;
993           case 'T': 
994             p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
995             ++psz_parser;
996             break;
997           default: ;
998           }
999         }
1000       
1001       num = strtol( psz_parser, &psz_next, 10 );
1002       if ( *psz_parser != '\0' && *psz_next == '\0') 
1003         {
1004           p_itemid->num = num;
1005         }
1006       
1007     }
1008
1009     if( !*psz_source ) {
1010
1011       /* No source specified, so figure it out. */
1012       if( !p_input->psz_access ) return NULL;
1013       
1014       psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
1015
1016       if( !psz_source || 0==strlen(psz_source) ) {
1017         /* Scan for a CD-ROM drive with a VCD in it. */
1018         char **cd_drives = cdio_get_devices_with_cap(NULL, 
1019                             (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
1020                              |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
1021                                                      true);
1022         if (NULL == cd_drives) return NULL;
1023         if (cd_drives[0] == NULL) {
1024           cdio_free_device_list(cd_drives);
1025           return NULL;
1026         }
1027         psz_source = strdup(cd_drives[0]);
1028         cdio_free_device_list(cd_drives);
1029       }
1030     }
1031
1032     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), 
1033                "source=%s entry=%d type=%d",
1034                psz_source, p_itemid->num, p_itemid->type);
1035
1036     return psz_source;
1037 }
1038
1039 /* 
1040    Set's start origin subsequent seeks/reads
1041 */
1042 static void 
1043 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn, 
1044               lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
1045 {
1046   thread_vcd_data_t * p_vcd  = (thread_vcd_data_t *) p_input->p_access_data;
1047
1048   p_vcd->origin_lsn = origin_lsn;
1049   p_vcd->cur_lsn    = cur_lsn;
1050   p_vcd->end_lsn    = end_lsn;
1051   p_vcd->cur_track  = cur_track;
1052   p_vcd->play_item.num  = cur_entry;
1053   p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1054   
1055   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
1056              "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
1057              origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
1058
1059   p_input->stream.p_selected_area->i_tell =
1060     (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
1061
1062   VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE, 
1063                 "chapter", "Setting entry");
1064 }
1065
1066 /*****************************************************************************
1067  * vcd_Open: Opens a VCD device or file and returns an opaque handle
1068  *****************************************************************************/
1069 static vcdinfo_obj_t *
1070 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
1071 {
1072     vcdinfo_obj_t *p_vcdobj;
1073     char  *actual_dev;
1074
1075     if( !psz_dev ) return NULL;
1076
1077     /* Set where to log errors messages from libcdio. */
1078     p_vcd_input = (input_thread_t *)p_this;
1079     cdio_log_set_handler ( cdio_log_handler );
1080     vcd_log_set_handler ( vcd_log_handler );
1081     
1082     actual_dev=strdup(psz_dev);
1083     if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) != 
1084          VCDINFO_OPEN_VCD) {
1085       free(actual_dev);
1086       return NULL;
1087     }
1088     free(actual_dev);
1089
1090     return p_vcdobj;
1091 }
1092
1093 /****************************************************************************
1094  * VCDReadSector: Read a sector (2324 bytes)
1095  ****************************************************************************/
1096 static int 
1097 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
1098                lsn_t cur_lsn, byte_t * p_buffer )
1099 {
1100   typedef struct {
1101     uint8_t subheader   [8];
1102     uint8_t data        [M2F2_SECTOR_SIZE];
1103   } vcdsector_t;
1104   vcdsector_t vcd_sector;
1105   
1106   if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd), 
1107                              &vcd_sector, cur_lsn, true) 
1108       != 0)
1109     {
1110       msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
1111       return -1;
1112     }
1113     
1114   memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
1115   
1116   return( 0 );
1117 }
1118
1119 /****************************************************************************
1120  Update the "varname" variable to i_num without triggering a callback.
1121 ****************************************************************************/
1122 static void
1123 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
1124               const char *varname, const char *label)
1125 {
1126   vlc_value_t val;
1127   val.i_int = i_num;
1128   if (NULL != p_vcd_input) {
1129     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1130     dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
1131   }
1132   var_Change( p_input, varname, i_action, &val, NULL );
1133 }