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