Rename access_t.psz_path to psz_location
[vlc/asuraparaju-public.git] / modules / access / vcdx / access.c
blob5d0aeff6f1288ed4ac802cd3a5c2c368edcbb0ec
1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo.
3 * vlc-specific things tend to go here.
4 *****************************************************************************
5 * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team
6 * $Id$
8 * Authors: Rocky Bernstein <rocky@panix.com>
9 * Some code is based on the non-libcdio VCD plugin (as there really
10 * isn't real developer documentation yet on how to write a
11 * navigable plugin.)
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
29 * Preamble
30 *****************************************************************************/
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
36 #include <vlc_common.h>
37 #include <vlc_interface.h>
38 #include <vlc_input.h>
39 #include <vlc_access.h>
40 #include <vlc_charset.h>
42 #include <cdio/cdio.h>
43 #include <cdio/cd_types.h>
44 #include <cdio/logging.h>
45 #include <cdio/util.h>
46 #include <libvcd/info.h>
47 #include <libvcd/logging.h>
48 #include "vcd.h"
49 #include "info.h"
50 #include "access.h"
52 /*****************************************************************************
53 * Local prototypes
54 *****************************************************************************/
56 /* First those which are accessed from outside (via pointers). */
57 static block_t *VCDReadBlock ( access_t * );
59 static int VCDControl ( access_t *p_access, int i_query,
60 va_list args );
62 /* Now those which are strictly internal */
63 static bool VCDEntryPoints ( access_t * );
64 static bool VCDLIDs ( access_t * );
65 static bool VCDSegments ( access_t * );
66 static int VCDTitles ( access_t * );
67 static char *VCDParse ( access_t *,
68 /*out*/ vcdinfo_itemid_t * p_itemid ,
69 /*out*/ bool *play_single_item );
71 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
72 const char *p_varname, char *p_label,
73 const char *p_debug_label );
75 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
77 /****************************************************************************
78 * Private functions
79 ****************************************************************************/
81 /* FIXME: This variable is a hack. Would be nice to eliminate the
82 global-ness. */
84 static access_t *p_vcd_access = NULL;
86 /* process messages that originate from libcdio. */
87 static void
88 cdio_log_handler (cdio_log_level_t level, const char message[])
90 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
91 switch (level) {
92 case CDIO_LOG_DEBUG:
93 case CDIO_LOG_INFO:
94 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
95 msg_Dbg( p_vcd_access, "%s", message);
96 break;
97 case CDIO_LOG_WARN:
98 msg_Warn( p_vcd_access, "%s", message);
99 break;
100 case CDIO_LOG_ERROR:
101 case CDIO_LOG_ASSERT:
102 msg_Err( p_vcd_access, "%s", message);
103 break;
104 default:
105 msg_Warn( p_vcd_access, "%s\n%s %d", message,
106 "The above message had unknown log level", level);
108 return;
111 /* process messages that originate from vcdinfo. */
112 static void
113 vcd_log_handler (vcd_log_level_t level, const char message[])
115 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
116 switch (level) {
117 case VCD_LOG_DEBUG:
118 case VCD_LOG_INFO:
119 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
120 msg_Dbg( p_vcd_access, "%s", message);
121 break;
122 case VCD_LOG_WARN:
123 msg_Warn( p_vcd_access, "%s", message);
124 break;
125 case VCD_LOG_ERROR:
126 case VCD_LOG_ASSERT:
127 msg_Err( p_vcd_access, "%s", message);
128 break;
129 default:
130 msg_Warn( p_vcd_access, "%s\n%s %d", message,
131 "The above message had unknown vcdimager log level", level);
133 return;
136 /*****************************************************************************
137 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
138 NULL is returned if something went wrong.
139 *****************************************************************************/
140 static block_t *
141 VCDReadBlock( access_t * p_access )
143 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
144 const int i_blocks = p_vcdplayer->i_blocks_per_read;
145 block_t *p_block;
146 int i_read;
147 uint8_t *p_buf;
149 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
150 (long unsigned int) p_vcdplayer->i_lsn );
152 /* Allocate a block for the reading */
153 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
155 msg_Err( p_access, "cannot get a new block of size: %i",
156 i_blocks * M2F2_SECTOR_SIZE );
157 block_Release( p_block );
158 return NULL;
161 p_buf = (uint8_t *) p_block->p_buffer;
162 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
164 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
166 p_access->info.i_pos += M2F2_SECTOR_SIZE;
168 switch ( read_status ) {
169 case READ_END:
170 /* End reached. Return NULL to indicated this. */
171 /* We also set the postion to the end so the higher level
172 (demux?) doesn't try to keep reading. If everything works out
173 right this shouldn't have to happen.
175 #if 0
176 if( p_access->info.i_pos != p_access->info.i_size ) {
177 msg_Warn( p_access,
178 "At end but pos (%llu) is not size (%llu). Adjusting.",
179 p_access->info.i_pos, p_access->info.i_size );
180 p_access->info.i_pos = p_access->info.i_size;
182 #endif
184 block_Release( p_block );
185 return NULL;
187 case READ_ERROR:
188 /* Some sort of error. Should we increment lsn? to skip block? */
189 block_Release( p_block );
190 return NULL;
191 case READ_STILL_FRAME:
192 /* FIXME The below should be done in an event thread.
193 Until then...
195 #if 1
196 msleep( INT64_C(1000) * *p_buf );
197 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn,
198 p_vcdplayer->i_track, &(p_vcdplayer->play_item));
199 // p_vcd->in_still = false;
200 dbg_print(INPUT_DBG_STILL, "still wait time done");
201 #else
202 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
203 #endif
205 block_Release( p_block );
206 return NULL;
208 default:
209 case READ_BLOCK:
210 /* Read buffer */
211 break;
214 p_buf += M2F2_SECTOR_SIZE;
215 /* Update seekpoint */
216 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
218 size_t i_entry = p_vcdplayer->play_item.num+1;
219 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
220 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
222 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
223 "entry change to %zu, current LSN %u >= end %u",
224 i_entry, p_vcdplayer->i_lsn, i_lsn);
226 p_vcdplayer->play_item.num = i_entry;
228 VCDSetOrigin( p_access, i_lsn, p_vcdplayer->i_track,
229 &(p_vcdplayer->play_item) );
234 return p_block;
238 /****************************************************************************
239 * VCDSeek
240 ****************************************************************************/
242 VCDSeek( access_t * p_access, uint64_t i_pos )
244 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
246 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
247 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
248 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
249 int i_seekpoint;
251 /* Next sector to read */
252 p_access->info.i_pos = i_pos;
253 p_vcdplayer->i_lsn = (i_pos / (uint64_t) M2F2_SECTOR_SIZE) +
254 p_vcdplayer->origin_lsn;
256 switch (p_vcdplayer->play_item.type)
258 case VCDINFO_ITEM_TYPE_TRACK:
259 case VCDINFO_ITEM_TYPE_ENTRY:
260 break;
261 default:
262 p_vcdplayer->b_valid_ep = false;
263 break;
266 /* Find entry */
267 if( p_vcdplayer->b_valid_ep )
269 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
271 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
273 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
274 "chapter", _("Entry"), "Setting entry" );
275 break;
280 vcdinfo_itemid_t itemid;
281 itemid.num = i_entry;
282 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
283 VCDSetOrigin(p_access, p_vcdplayer->i_lsn,
284 p_vcdplayer->i_track, &itemid);
288 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
289 "orig %lu, cur: %lu, offset: %"PRIi64", entry %d",
290 (long unsigned int) p_vcdplayer->origin_lsn,
291 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
292 i_entry );
294 /* Find seekpoint */
295 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
297 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
298 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
301 /* Update current seekpoint */
302 if( i_seekpoint != p_access->info.i_seekpoint )
304 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
305 (long unsigned int) i_seekpoint );
306 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
307 p_access->info.i_seekpoint = i_seekpoint;
310 p_access->info.b_eof = false;
311 return VLC_SUCCESS;
314 /*****************************************************************************
315 VCDEntryPoints: Reads the information about the entry points on the disc
316 and initializes area information with that.
317 Before calling this track information should have been read in.
318 *****************************************************************************/
319 static bool
320 VCDEntryPoints( access_t * p_access )
322 if (!p_access || !p_access->p_sys) return false;
324 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
325 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdplayer->vcd);
326 const track_t i_last_track
327 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
328 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
329 unsigned int i;
331 if (0 == i_entries) {
332 LOG_ERR ("no entires found -- something is wrong" );
333 return false;
336 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
338 if( p_vcdplayer->p_entries == NULL )
340 LOG_ERR ("not enough memory for entry points treatment" );
341 return false;
344 p_vcdplayer->i_entries = i_entries;
346 for( i = 0 ; i < i_entries ; i++ )
348 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
349 if( i_track <= i_last_track )
351 seekpoint_t *s = vlc_seekpoint_New();
352 char psz_entry[100];
354 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
356 p_vcdplayer->p_entries[i] =
357 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
359 s->psz_name = strdup(psz_entry);
360 s->i_byte_offset = (p_vcdplayer->p_entries[i]
361 - vcdinfo_get_track_lsn(p_vcdplayer->vcd,i_track))
362 * M2F2_SECTOR_SIZE;
364 dbg_print( INPUT_DBG_MRL, "%s, lsn %d, byte_offset %ld",
365 s->psz_name, p_vcdplayer->p_entries[i],
366 (unsigned long int) s->i_byte_offset);
367 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
368 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
370 } else
371 msg_Warn( p_access, "wrong track number found in entry points" );
373 p_vcdplayer->b_valid_ep = true;
374 return true;
377 /*****************************************************************************
378 * VCDSegments: Reads the information about the segments the disc.
379 *****************************************************************************/
380 static bool
381 VCDSegments( access_t * p_access )
383 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
384 unsigned int i;
385 input_title_t *t;
387 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
389 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
390 "Segments: %d", p_vcdplayer->i_segments);
392 if ( 0 == p_vcdplayer->i_segments ) return false;
394 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
395 p_vcdplayer->i_titles++;
397 t->i_size = 0; /* Not sure Segments have a size associated */
398 t->psz_name = strdup(_("Segments"));
400 /* We have one additional segment allocated so we can get the size
401 by subtracting seg[i+1] - seg[i].
403 p_vcdplayer->p_segments=malloc(sizeof(lsn_t)*(p_vcdplayer->i_segments+1));
404 if( p_vcdplayer->p_segments == NULL )
406 LOG_ERR ("not enough memory for segment treatment" );
407 return false;
410 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
412 char psz_segment[100];
413 seekpoint_t *s = vlc_seekpoint_New();
414 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
416 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
417 i );
419 s->i_byte_offset = 0; /* Not sure what this would mean here */
420 s->psz_name = strdup(psz_segment);
421 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
424 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
425 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
426 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
427 p_vcdplayer->i_segments-1);
429 return true;
432 /*****************************************************************************
433 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
435 We start area addressing for tracks at 1 since the default area 0
436 is reserved for segments.
437 *****************************************************************************/
438 static int
439 VCDTitles( access_t * p_access )
441 /* We'll assume a VCD has its first MPEG track
442 cdio_get_first_track_num()+1 could be used if one wanted to be
443 very careful about this. Note: cdio_get_first_track() will give the
444 ISO-9660 track before the MPEG tracks.
447 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
450 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
451 track_t i;
453 p_vcdplayer->i_titles = 0;
454 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
456 input_title_t *t = p_vcdplayer->p_title[i-1] =
457 vlc_input_title_New();
458 char psz_track[80];
460 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"), i );
461 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
462 i ) * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
463 t->psz_name = strdup(psz_track);
465 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %"PRIi64, i, t->i_size );
467 p_vcdplayer->i_titles++;
470 return VLC_SUCCESS;
474 /*****************************************************************************
475 VCDLIDs: Reads the LIST IDs from the LOT.
476 *****************************************************************************/
477 static bool
478 VCDLIDs( access_t * p_access )
480 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
481 input_title_t *t;
482 unsigned int i_lid, i_title;
484 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
485 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
487 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
488 "LIDs: %d", p_vcdplayer->i_lids);
490 if ( 0 == p_vcdplayer->i_lids ) return false;
492 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
494 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
496 #ifdef FIXED
498 We need to change libvcdinfo to be more robust when there are
499 problems reading the extended PSD. Given that area-highlighting and
500 selection features in the extended PSD haven't been implemented,
501 it's best then to not try to read this at all.
503 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
504 vcdinfo_visit_lot (p_vcdplayer->vcd, true);
505 #endif
508 /* Set up LIDs Navigation Menu */
509 t = vlc_input_title_New();
510 t->b_menu = true;
511 t->psz_name = strdup( "LIDs" );
513 i_title = p_vcdplayer->i_tracks;
514 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
516 char psz_lid[100];
517 seekpoint_t *s = vlc_seekpoint_New();
519 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"), i_lid );
521 s->i_byte_offset = 0; /* A lid doesn't have an offset
522 size associated with it */
523 s->psz_name = strdup(psz_lid);
524 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
527 #ifdef DYNAMICALLY_ALLOCATED
528 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
529 #else
530 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
531 p_vcdplayer->i_titles++;
532 #endif
534 return true;
537 /*****************************************************************************
538 * VCDParse: parse command line
539 *****************************************************************************/
540 static char *
541 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
542 /*out*/ bool *play_single_item )
544 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
545 char *psz_parser;
546 char *psz_source;
547 char *psz_next;
549 if( var_InheritInteger( p_access, MODULE_STRING "-PBC" ) ) {
550 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
551 p_itemid->num = 1;
552 *play_single_item = false;
554 else
556 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
557 p_itemid->num = 0;
560 #ifdef WIN32
561 /* On Win32 we want the VCD access plugin to be explicitly requested,
562 * we end up with lots of problems otherwise */
563 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
564 #endif
566 if( !p_access->psz_location )
568 return NULL;
571 psz_parser = psz_source = strdup( p_access->psz_location );
573 /* Parse input string :
574 * [device][@[type][title]] */
575 while( *psz_parser && *psz_parser != '@' )
577 psz_parser++;
580 if( *psz_parser == '@' )
582 /* Found the divide between the source name and the
583 type+entry number. */
584 unsigned int num;
586 *psz_parser = '\0';
587 ++psz_parser;
588 if( *psz_parser )
589 switch(*psz_parser) {
590 case 'E':
591 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
592 ++psz_parser;
593 *play_single_item = true;
594 break;
595 case 'P':
596 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
597 ++psz_parser;
598 *play_single_item = false;
599 break;
600 case 'S':
601 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
602 ++psz_parser;
603 *play_single_item = true;
604 break;
605 case 'T':
606 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
607 ++psz_parser;
608 *play_single_item = true;
609 break;
610 default:
611 break;
614 num = strtol( psz_parser, &psz_next, 10 );
615 if ( *psz_parser != '\0' && *psz_next == '\0')
617 p_itemid->num = num;
620 } else {
621 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
625 if( !*psz_source )
628 /* No source specified, so figure it out. */
629 if( !p_access->psz_access ) return NULL;
631 psz_source = var_InheritString( p_access, "vcd" );
633 if( !psz_source )
635 /* Scan for a CD-ROM drive with a VCD in it. */
636 char **cd_drives = cdio_get_devices_with_cap(NULL,
637 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
638 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
639 true);
640 if( NULL == cd_drives ) return NULL;
641 if( cd_drives[0] == NULL )
643 cdio_free_device_list( cd_drives );
644 return NULL;
646 psz_source = strdup( cd_drives[0] );
647 cdio_free_device_list( cd_drives );
651 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
652 "source=%s entry=%d type=%d",
653 psz_source, p_itemid->num, p_itemid->type);
655 return psz_source;
659 Sets start origin for subsequent seeks/reads
661 void
662 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
663 const vcdinfo_itemid_t *p_itemid )
665 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
667 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
668 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn, i_track );
670 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
672 switch (p_vcdplayer->play_item.type)
674 case VCDINFO_ITEM_TYPE_ENTRY:
675 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
676 "chapter", _("Entry"), "Setting entry/segment");
677 p_access->info.i_title = i_track-1;
678 if (p_vcdplayer->b_track_length)
680 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
681 p_access->info.i_pos = (uint64_t) M2F2_SECTOR_SIZE *
682 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track)-i_lsn);
683 } else {
684 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
685 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd,p_itemid->num);
686 p_access->info.i_pos = 0;
688 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %"PRIu64", pos: %"PRIu64,
689 p_access->info.i_size, p_access->info.i_pos );
690 p_access->info.i_seekpoint = p_itemid->num;
691 break;
693 case VCDINFO_ITEM_TYPE_SEGMENT:
694 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
695 "chapter", _("Segment"), "Setting entry/segment");
696 /* The last title entry is the for segments (when segments exist
697 and they must here. The segment seekpoints are stored after
698 the entry seekpoints and (zeroed) lid seekpoints.
700 p_access->info.i_title = p_vcdplayer->i_titles - 1;
701 p_access->info.i_size = 0; /* No seeking on stills, please. */
702 p_access->info.i_pos = 0;
703 p_access->info.i_seekpoint = p_vcdplayer->i_entries
704 + p_vcdplayer->i_lids + p_itemid->num;
705 break;
707 case VCDINFO_ITEM_TYPE_TRACK:
708 p_access->info.i_title = i_track-1;
709 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
710 p_access->info.i_pos = 0;
711 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
712 i_track);
713 break;
715 default:
716 msg_Warn( p_access, "can't set origin for play type %d",
717 p_vcdplayer->play_item.type );
720 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
721 |INPUT_UPDATE_SEEKPOINT;
723 VCDUpdateTitle( p_access );
727 /*****************************************************************************
728 * vcd_Open: Opens a VCD device or file initializes, a list of
729 tracks, segements and entry lsns and sizes and returns an opaque handle.
730 *****************************************************************************/
731 static vcdinfo_obj_t *
732 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
734 access_t *p_access = (access_t *)p_this;
735 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
736 vcdinfo_obj_t *p_vcdobj;
737 char *actual_dev;
738 unsigned int i;
740 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
742 if( !psz_dev ) return NULL;
744 actual_dev= ToLocaleDup(psz_dev);
745 if( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
746 VCDINFO_OPEN_VCD)
748 free(actual_dev);
749 return NULL;
751 free(actual_dev);
754 Save summary info on tracks, segments and entries...
757 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) )
759 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
760 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
762 for (i=0; i<p_vcdplayer->i_tracks; i++)
764 unsigned int track_num=i+1;
765 p_vcdplayer->track[i].size =
766 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
767 p_vcdplayer->track[i].start_LSN =
768 vcdinfo_get_track_lsn(p_vcdobj, track_num);
770 } else
771 p_vcdplayer->track = NULL;
773 if( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) )
775 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
776 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
778 for (i=0; i<p_vcdplayer->i_entries; i++)
780 p_vcdplayer->entry[i].size =
781 vcdinfo_get_entry_sect_count(p_vcdobj, i);
782 p_vcdplayer->entry[i].start_LSN =
783 vcdinfo_get_entry_lsn(p_vcdobj, i);
785 } else
786 p_vcdplayer->entry = NULL;
788 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) )
790 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
791 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
793 for (i=0; i<p_vcdplayer->i_segments; i++)
795 p_vcdplayer->segment[i].size =
796 vcdinfo_get_seg_sector_count(p_vcdobj, i);
797 p_vcdplayer->segment[i].start_LSN =
798 vcdinfo_get_seg_lsn(p_vcdobj, i);
800 } else
801 p_vcdplayer->segment = NULL;
803 return p_vcdobj;
806 /****************************************************************************
807 Update the "varname" variable to i_num without triggering a callback.
808 ****************************************************************************/
809 static void
810 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
811 const char *p_varname, char *p_label,
812 const char *p_debug_label)
814 vlc_value_t val;
815 val.i_int = i_num;
816 if( p_access )
818 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
819 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
821 if( p_label )
823 vlc_value_t text;
824 text.psz_string = p_label;
825 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
827 var_Change( p_access, p_varname, i_action, &val, NULL );
831 /*****************************************************************************
832 * Public routines.
833 *****************************************************************************/
835 /*****************************************************************************
836 VCDOpen: open VCD.
837 read in meta-information about VCD: the number of tracks, segments,
838 entries, size and starting information. Then set up state variables so
839 that we read/seek starting at the location specified.
841 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
842 and VLC_EGENERIC for some other error.
843 *****************************************************************************/
845 VCDOpen ( vlc_object_t *p_this )
847 access_t *p_access = (access_t *)p_this;
848 vcdplayer_t *p_vcdplayer;
849 char *psz_source;
850 vcdinfo_itemid_t itemid;
851 bool play_single_item = false;
853 p_access->pf_read = NULL;
854 p_access->pf_block = VCDReadBlock;
855 p_access->pf_control = VCDControl;
856 p_access->pf_seek = VCDSeek;
858 p_access->info.i_update = 0;
859 p_access->info.i_size = 0;
860 p_access->info.i_pos = 0;
861 p_access->info.b_eof = false;
862 p_access->info.i_title = 0;
863 p_access->info.i_seekpoint = 0;
865 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
867 if( p_vcdplayer == NULL )
868 return VLC_ENOMEM;
870 p_vcdplayer->i_debug = var_InheritInteger( p_this, MODULE_STRING "-debug" );
871 p_access->p_sys = (access_sys_t *) p_vcdplayer;
873 /* Set where to log errors messages from libcdio. */
874 p_vcd_access = p_access;
875 cdio_log_set_handler ( cdio_log_handler );
876 vcd_log_set_handler ( vcd_log_handler );
878 psz_source = VCDParse( p_access, &itemid, &play_single_item );
880 if ( NULL == psz_source )
882 free( p_vcdplayer );
883 return( VLC_EGENERIC );
886 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
887 psz_source, p_access->psz_location );
889 p_vcdplayer->psz_source = strdup(psz_source);
890 p_vcdplayer->i_blocks_per_read = var_InheritInteger( p_this, MODULE_STRING
891 "-blocks-per-read" );
892 p_vcdplayer->b_track_length = var_InheritInteger( p_this, MODULE_STRING
893 "-track-length" );
894 p_vcdplayer->in_still = false;
895 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
896 p_vcdplayer->p_input = access_GetParentInput( p_access );
897 // p_vcdplayer->p_meta = vlc_meta_New();
898 p_vcdplayer->p_segments = NULL;
899 p_vcdplayer->p_entries = NULL;
901 /* set up input */
903 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
905 goto err_exit;
908 p_vcdplayer->b_svd = vcdinfo_get_tracksSVD(p_vcdplayer->vcd);
910 /* Get track information. */
911 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
913 if( p_vcdplayer->i_tracks<1 || CDIO_INVALID_TRACK==p_vcdplayer->i_tracks )
915 vcdinfo_close( p_vcdplayer->vcd );
916 LOG_ERR ("no movie tracks found" );
917 goto err_exit;
920 /* Build Navigation Title table for the tracks. */
921 VCDTitles( p_access );
923 /* Add into the above entry points as "Chapters". */
924 if( ! VCDEntryPoints( p_access ) )
926 msg_Warn( p_access, "could not read entry points, will not use them" );
927 p_vcdplayer->b_valid_ep = false;
930 /* Initialize LID info and add that as a menu item */
931 if( ! VCDLIDs( p_access ) )
933 msg_Warn( p_access, "could not read entry LIDs" );
936 /* Do we set PBC (via LID) on? */
937 p_vcdplayer->i_lid =
938 ( VCDINFO_ITEM_TYPE_LID == itemid.type
939 && p_vcdplayer->i_lids > itemid.num )
940 ? itemid.num
941 : VCDINFO_INVALID_ENTRY;
943 /* Initialize segment information and add that a "Track". */
944 VCDSegments( p_access );
946 vcdplayer_play( p_access, itemid );
948 free( p_access->psz_demux );
949 p_access->psz_demux = strdup( "ps" );
951 #ifdef FIXED
952 if( play_single_item )
953 VCDFixupPlayList(p_access,p_vcd,psz_source,&itemid,play_single_item);
954 #endif
956 #ifdef FIXED
957 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
958 p_vcdplayer->p_intf->b_block = false;
959 #endif
960 p_vcdplayer->p_access = p_access;
962 free( psz_source );
964 return VLC_SUCCESS;
965 err_exit:
966 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
967 free( psz_source );
968 free( p_vcdplayer->psz_source );
969 free( p_vcdplayer );
970 return VLC_EGENERIC;
973 /*****************************************************************************
974 * VCDClose: closes VCD releasing allocated memory.
975 *****************************************************************************/
976 void
977 VCDClose ( vlc_object_t *p_this )
979 access_t *p_access = (access_t *)p_this;
980 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
982 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
985 unsigned int i;
986 for (i=0 ; i<p_vcdplayer->i_titles; i++)
987 if (p_vcdplayer->p_title[i])
988 free(p_vcdplayer->p_title[i]->psz_name);
991 vcdinfo_close( p_vcdplayer->vcd );
993 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
995 FREENULL( p_vcdplayer->p_entries );
996 FREENULL( p_vcdplayer->p_segments );
997 FREENULL( p_vcdplayer->psz_source );
998 FREENULL( p_vcdplayer->track );
999 FREENULL( p_vcdplayer->segment );
1000 FREENULL( p_vcdplayer->entry );
1001 FREENULL( p_access->psz_demux );
1002 FREENULL( p_vcdplayer );
1003 p_vcd_access = NULL;
1006 /*****************************************************************************
1007 * Control: The front-end or vlc engine calls here to ether get
1008 * information such as meta information or plugin capabilities or to
1009 * issue miscellaneous "set" requests.
1010 *****************************************************************************/
1011 static int VCDControl( access_t *p_access, int i_query, va_list args )
1013 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1014 int *pi_int;
1015 int i;
1017 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1018 "query %d", i_query );
1020 switch( i_query )
1022 /* Pass back a copy of meta information that was gathered when we
1023 during the Open/Initialize call.
1025 case ACCESS_GET_META:
1026 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1027 #if 0
1028 if( p_vcdplayer->p_meta )
1030 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg(args,vlc_meta_t**);
1032 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1033 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1035 else
1036 #endif
1037 msg_Warn( p_access, "tried to copy NULL meta info" );
1039 return VLC_SUCCESS;
1041 case ACCESS_CAN_SEEK:
1042 case ACCESS_CAN_FASTSEEK:
1043 case ACCESS_CAN_PAUSE:
1044 case ACCESS_CAN_CONTROL_PACE:
1046 dbg_print( INPUT_DBG_EVENT,
1047 "seek/fastseek/pause/can_control_pace" );
1048 *((bool*)va_arg( args, bool* )) = true;
1049 return VLC_SUCCESS;
1051 /* */
1052 case ACCESS_GET_PTS_DELAY:
1053 *(int64_t*)va_arg(args,int64_t *) = INT64_C(1000) *
1054 var_GetInteger( p_access, MODULE_STRING "-caching" );
1055 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1056 return VLC_SUCCESS;
1058 /* */
1059 case ACCESS_SET_PAUSE_STATE:
1060 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1061 return VLC_SUCCESS;
1063 case ACCESS_GET_TITLE_INFO:
1065 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1066 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1067 input_title_t ***ppp_title
1068 = (input_title_t***)va_arg( args, input_title_t*** );
1069 char *psz_mrl = malloc( psz_mrl_max );
1070 unsigned int i;
1072 pi_int = (int*)va_arg( args, int* );
1074 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1075 p_vcdplayer->i_titles );
1077 if( psz_mrl )
1079 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1080 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1081 VCDMetaInfo( p_access, psz_mrl );
1082 free(psz_mrl);
1085 /* Duplicate title info */
1086 if( p_vcdplayer->i_titles == 0 )
1088 *pi_int = 0; ppp_title = NULL;
1089 return VLC_SUCCESS;
1091 *pi_int = p_vcdplayer->i_titles;
1092 *ppp_title = malloc(sizeof(input_title_t **)*p_vcdplayer->i_titles);
1094 if (!*ppp_title) return VLC_ENOMEM;
1096 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1097 if( p_vcdplayer->p_title[i] )
1098 (*ppp_title)[i] =
1099 vlc_input_title_Duplicate(p_vcdplayer->p_title[i]);
1101 break;
1103 case ACCESS_SET_TITLE:
1104 i = (int)va_arg( args, int );
1106 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1107 if( i != p_access->info.i_title )
1109 vcdinfo_itemid_t itemid;
1110 track_t i_track = i+1;
1111 unsigned int i_entry =
1112 vcdinfo_track_get_entry(p_vcdplayer->vcd,i_track);
1114 if( i < p_vcdplayer->i_tracks )
1116 /* FIXME! For now we are assuming titles are only
1117 tracks and that track == title+1 */
1118 itemid.num = i_track;
1119 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1121 else
1123 /* FIXME! i_tracks+2 are Segments, but we need to be able
1124 to figure out which segment of that. i_tracks+1 is
1125 either Segments (if no LIDs) or LIDs otherwise. Again
1126 need a way to get the LID number. */
1128 msg_Warn(p_access,"Trying to set track (%u) beyond end "
1129 "of last track (%u).",i+1,p_vcdplayer->i_tracks);
1130 return VLC_EGENERIC;
1133 VCDSetOrigin(p_access,
1134 vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i_entry),
1135 i_track, &itemid);
1137 break;
1139 case ACCESS_SET_SEEKPOINT:
1141 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1142 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1144 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1145 if( t->i_seekpoint > 0 )
1147 track_t i_track = p_access->info.i_title+1;
1148 lsn_t lsn;
1150 /* FIXME! For now we are assuming titles are only tracks and
1151 that track == title+1 and we the play item is entries (not
1152 tracks or lids). We need to generalize all of this.
1155 if (i < p_vcdplayer->i_entries)
1157 p_vcdplayer->play_item.num = i;
1158 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1159 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1160 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1162 p_vcdplayer->play_item.num = i = i - p_vcdplayer->i_entries;
1163 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1164 lsn = 0;
1165 } else
1167 p_vcdplayer->play_item.num = i
1168 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1169 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1170 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1173 VCDSetOrigin(p_access,vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i),
1174 i_track,&(p_vcdplayer->play_item));
1176 return VLC_SUCCESS;
1179 case ACCESS_SET_PRIVATE_ID_STATE:
1180 dbg_print( INPUT_DBG_EVENT, "set private id" );
1181 return VLC_EGENERIC;
1183 default:
1184 msg_Warn( p_access, "unimplemented query in control" );
1185 return VLC_EGENERIC;
1188 return VLC_SUCCESS;