]> git.sesse.net Git - vlc/blob - modules/access/vcdx/access.c
Reorganize more analogous to dvdplay. Should give some growing room to
[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.3 2003/11/20 03:56:22 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   VCDOpen: 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_(VCDOpen) ( 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  * VCDClose: closes VCD releasing allocated memory.
304  *****************************************************************************/
305 void 
306 E_(VCDClose) ( 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     p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
943     p_itemid->num=1;
944     
945 #ifdef WIN32
946     /* On Win32 we want the VCD access plugin to be explicitly requested,
947      * we end up with lots of problems otherwise */
948     if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
949 #endif
950
951     if( !p_input->psz_name )
952     {
953         return NULL;
954     }
955
956     psz_parser = psz_source = strdup( p_input->psz_name );
957
958     /* Parse input string :
959      * [device][@[type][title]] */
960     while( *psz_parser && *psz_parser != '@' )
961     {
962         psz_parser++;
963     }
964
965     if( *psz_parser == '@' )
966     {
967       /* Found the divide between the source name and the 
968          type+entry number. */
969       unsigned int num;
970       
971       *psz_parser = '\0';
972       ++psz_parser;
973       if( *psz_parser )
974         {
975           switch(*psz_parser) {
976           case 'E': 
977             p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
978             ++psz_parser;
979             break;
980           case 'P': 
981             p_itemid->type = VCDINFO_ITEM_TYPE_LID;
982             ++psz_parser;
983             break;
984           case 'S': 
985             p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
986             ++psz_parser;
987             break;
988           case 'T': 
989             p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
990             ++psz_parser;
991             break;
992           default: ;
993           }
994         }
995       
996       num = strtol( psz_parser, &psz_next, 10 );
997       if ( *psz_parser != '\0' && *psz_next == '\0') 
998         {
999           p_itemid->num = num;
1000         }
1001       
1002     }
1003
1004     if( !*psz_source ) {
1005
1006       /* No source specified, so figure it out. */
1007       if( !p_input->psz_access ) return NULL;
1008       
1009       psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
1010
1011       if( !psz_source ) {
1012         /* Scan for a CD with a VCD in it. */
1013         char **cd_drives = cdio_get_devices_with_cap(NULL, 
1014                             (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
1015                              |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
1016                                                      true);
1017         if (NULL == cd_drives) return NULL;
1018         if (cd_drives[0] == NULL) {
1019           cdio_free_device_list(cd_drives);
1020           return NULL;
1021         }
1022         psz_source = strdup(cd_drives[0]);
1023         cdio_free_device_list(cd_drives);
1024       }
1025     }
1026
1027     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), 
1028                "source=%s entry=%d type=%d",
1029                psz_source, p_itemid->num, p_itemid->type);
1030
1031     return psz_source;
1032 }
1033
1034 /* 
1035    Set's start origin subsequent seeks/reads
1036 */
1037 static void 
1038 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn, 
1039               lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
1040 {
1041   thread_vcd_data_t * p_vcd  = (thread_vcd_data_t *) p_input->p_access_data;
1042
1043   p_vcd->origin_lsn = origin_lsn;
1044   p_vcd->cur_lsn    = cur_lsn;
1045   p_vcd->end_lsn    = end_lsn;
1046   p_vcd->cur_track  = cur_track;
1047   p_vcd->play_item.num  = cur_entry;
1048   p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1049   
1050   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
1051              "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
1052              origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
1053
1054   p_input->stream.p_selected_area->i_tell =
1055     (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
1056
1057   VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE, 
1058                 "chapter", "Setting entry");
1059 }
1060
1061 /*****************************************************************************
1062  * vcd_Open: Opens a VCD device or file and returns an opaque handle
1063  *****************************************************************************/
1064 static vcdinfo_obj_t *
1065 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
1066 {
1067     vcdinfo_obj_t *p_vcdobj;
1068     char  *actual_dev;
1069
1070     if( !psz_dev ) return NULL;
1071
1072     /* Set where to log errors messages from libcdio. */
1073     p_vcd_input = (input_thread_t *)p_this;
1074     cdio_log_set_handler ( cdio_log_handler );
1075     vcd_log_set_handler ( vcd_log_handler );
1076     
1077     actual_dev=strdup(psz_dev);
1078     if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) != 
1079          VCDINFO_OPEN_VCD) {
1080       free(actual_dev);
1081       return NULL;
1082     }
1083     free(actual_dev);
1084
1085     return p_vcdobj;
1086 }
1087
1088 /****************************************************************************
1089  * VCDReadSector: Read a sector (2324 bytes)
1090  ****************************************************************************/
1091 static int 
1092 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
1093                lsn_t cur_lsn, byte_t * p_buffer )
1094 {
1095   typedef struct {
1096     uint8_t subheader   [8];
1097     uint8_t data        [M2F2_SECTOR_SIZE];
1098   } vcdsector_t;
1099   vcdsector_t vcd_sector;
1100   
1101   if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd), 
1102                              &vcd_sector, cur_lsn, true) 
1103       != 0)
1104     {
1105       msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
1106       return -1;
1107     }
1108     
1109   memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
1110   
1111   return( 0 );
1112 }
1113
1114 /****************************************************************************
1115  Update the "varname" variable to i_num without triggering a callback.
1116 ****************************************************************************/
1117 static void
1118 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
1119               const char *varname, const char *label)
1120 {
1121   vlc_value_t val;
1122   val.i_int = i_num;
1123   if (NULL != p_vcd_input) {
1124     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1125     dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
1126   }
1127   var_Change( p_input, varname, i_action, &val, NULL );
1128 }