1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc
3 * using libcdio, libvcd and libvcdinfo. vlc-specific things tend
5 *****************************************************************************
6 * Copyright (C) 2000, 2003 VideoLAN
7 * $Id: access.c,v 1.10 2003/12/11 12:56:25 rocky Exp $
9 * Authors: Rocky Bernstein <rocky@panix.com>
10 * Johan Bilien <jobi@via.ecp.fr>
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.
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.
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 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
32 #include <vlc/input.h>
35 #include "../../demux/mpeg/system.h"
37 #include "vcdplayer.h"
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>
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)
53 #define VCD_MRL_PREFIX "vcdx://"
55 /*****************************************************************************
57 *****************************************************************************/
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 * );
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,
74 static char *VCDParse ( input_thread_t *,
75 /*out*/ vcdinfo_itemid_t * p_itemid );
77 static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
78 const char *varname, const char *label );
80 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
82 /****************************************************************************
84 ****************************************************************************/
86 /* FIXME: This variable is a hack. Would be nice to eliminate the
89 static input_thread_t *p_vcd_input = NULL;
91 /* process messages that originate from libcdio. */
93 cdio_log_handler (cdio_log_level_t level, const char message[])
95 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
99 if (p_vcd->i_debug & INPUT_DBG_CDIO)
100 msg_Dbg( p_vcd_input, message);
103 msg_Warn( p_vcd_input, message);
106 case CDIO_LOG_ASSERT:
107 msg_Err( p_vcd_input, message);
110 msg_Warn( p_vcd_input, message,
111 _("The above message had unknown log level"),
117 /* process messages that originate from vcdinfo. */
119 vcd_log_handler (vcd_log_level_t level, const char message[])
121 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
125 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
126 msg_Dbg( p_vcd_input, message);
129 msg_Warn( p_vcd_input, message);
133 msg_Err( p_vcd_input, message);
136 msg_Warn( p_vcd_input, "%s\n%s %d", message,
137 _("The above message had unknown vcdimager log level"),
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
148 *****************************************************************************/
150 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
152 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
156 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
160 dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn );
162 /* Compute the number of blocks we have to read */
164 i_blocks = i_len / M2F2_SECTOR_SIZE;
166 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
169 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
170 vcdplayer_read_status_t read_status;
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 );
176 read_status = vcdplayer_pbc_is_on( p_vcd )
177 ? vcdplayer_pbc_nav( p_input )
178 : vcdplayer_non_pbc_nav( p_input );
180 switch (read_status) {
182 /* End reached. Return NULL to indicated this. */
184 /* Some sort of error. */
187 case READ_STILL_FRAME:
189 /* Reached the end of a still frame. */
191 byte_t * p_buf = p_buffer;
192 pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
194 p_buf += (i_index*M2F2_SECTOR_SIZE);
195 memset(p_buf, 0, M2F2_SECTOR_SIZE);
198 dbg_print(INPUT_DBG_STILL, "Handled still event");
201 p_vcd->p_intf->p_sys->b_still = 1;
202 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
205 vlc_mutex_lock( &p_input->stream.stream_lock );
207 p_pgrm = p_input->stream.p_selected_program;
208 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
210 vlc_mutex_unlock( &p_input->stream.stream_lock );
212 input_ClockManageControl( p_input, p_pgrm, 0 );
214 p_vcd->p_intf->p_sys->b_still = 1;
215 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
217 return i_read + M2F2_SECTOR_SIZE;
225 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
227 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
229 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
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 )
242 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
244 vlc_mutex_lock( &p_input->stream.stream_lock );
246 if( i_entry < p_vcd->num_entries &&
247 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
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" );
259 vlc_mutex_unlock( &p_input->stream.stream_lock );
262 i_read += M2F2_SECTOR_SIZE;
265 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
267 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
268 p_vcd->cur_lsn, p_last_sector ) < 0 )
270 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
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;
283 /*****************************************************************************
284 * VCDSetProgram: Does nothing since a VCD is mono_program
285 *****************************************************************************/
287 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
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" );
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 ****************************************************************************/
303 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
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;
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 );
317 /* we can't use the interface slider until initilization is complete */
318 p_input->stream.b_seekable = 0;
320 if( p_area != p_input->stream.p_selected_area )
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;
328 /* Change the default area */
329 p_input->stream.p_selected_area = p_area;
331 /* Update the navigation variables without triggering a callback */
332 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
335 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
336 for( i = p_area->i_plugin_data; i < i_nb; i++ )
338 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
339 "chapter", "Adding entry choice");
344 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
345 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
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],
353 p_input->stream.b_seekable = old_seekable;
354 /* warn interface that something has changed */
355 p_input->stream.b_changed = 1;
361 /****************************************************************************
363 ****************************************************************************/
365 VCDSeek( input_thread_t * p_input, off_t i_off )
367 thread_vcd_data_t * p_vcd;
368 unsigned int i_entry=0; /* invalid entry */
370 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
372 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
374 vlc_mutex_lock( &p_input->stream.stream_lock );
375 #define p_area p_input->stream.p_selected_area
377 if( p_vcd->b_valid_ep )
379 for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
381 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
383 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
384 "chapter", "Setting entry" );
388 p_vcd->play_item.num = p_area->i_part = i_entry;
389 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
393 p_input->stream.p_selected_area->i_tell = i_off;
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 );
400 vlc_mutex_unlock( &p_input->stream.stream_lock );
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 *****************************************************************************/
411 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
413 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
414 input_area_t * p_area;
416 p_vcd->in_still = false;
418 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
419 itemid.num, itemid.type);
421 #define area p_input->stream.pp_areas
423 switch (itemid.type) {
424 case VCDINFO_ITEM_TYPE_TRACK:
426 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
429 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
430 LOG_ERR ("Invalid track number %d", itemid.num );
433 p_area = area[itemid.num];
434 p_area->i_part = p_area->i_plugin_data;
435 p_input->stream.b_seekable = 1;
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 );
443 vcdinfo_video_segment_type_t segtype =
444 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
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);
451 p_area->i_part = itemid.num;
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;
463 p_input->stream.b_seekable = 1;
464 p_vcd->in_still = false;
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 );
475 p_vcd->cur_lid = itemid.num;
476 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
478 switch (p_vcd->pxd.descriptor_type) {
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;
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 );
494 case PSD_TYPE_PLAY_LIST: {
495 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
497 return vcdplayer_inc_play_item(p_input)
498 ? VLC_SUCCESS : VLC_EGENERIC;
502 case PSD_TYPE_END_LIST:
503 case PSD_TYPE_COMMAND_LIST:
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 );
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;
523 LOG_ERR ("unknown entry type" );
527 VCDSetArea( p_input, p_area );
531 p_vcd->play_item = itemid;
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 );
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 *****************************************************************************/
547 VCDEntryPoints( input_thread_t * p_input )
549 thread_vcd_data_t * p_vcd;
551 unsigned int i, i_entry_index = 0;
552 unsigned int i_previous_track = CDIO_INVALID_TRACK;
554 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
556 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
560 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
562 if( p_vcd->p_entries == NULL )
564 LOG_ERR ("not enough memory for entry points treatment" );
568 p_vcd->num_entries = 0;
570 for( i = 0 ; i < i_nb ; i++ )
572 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
573 if( i_track <= p_input->stream.i_area_nb )
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 ++;
579 /* if this entry belongs to a new track */
580 if( i_track != i_previous_track )
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 =
585 i_previous_track = i_track;
586 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
589 p_vcd->num_entries ++;
592 msg_Warn( p_input, "wrong track number found in entry points" );
594 p_vcd->b_valid_ep = true;
598 /*****************************************************************************
599 * VCDSegments: Reads the information about the segments the disc.
600 *****************************************************************************/
602 VCDSegments( input_thread_t * p_input )
604 thread_vcd_data_t * p_vcd;
606 unsigned int num_segments;
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);
612 #define area p_input->stream.pp_areas
614 /* area 0 is reserved for segments. Set Absolute start offset
616 area[0]->i_plugin_data = 0;
617 input_DelArea( p_input, area[0] );
618 input_AddArea( p_input, 0, 0 );
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;
625 /* Default Segment */
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;
632 area[0]->i_part_nb = 0;
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 );
638 if (num_segments == 0) return 0;
640 /* We have one additional segment allocated so we can get the size
641 by subtracting seg[i+1] - seg[i].
643 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
644 if( p_vcd->p_segments == NULL )
646 LOG_ERR ("not enough memory for segment treatment" );
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 );
654 for( i = 0 ; i < num_segments ; i++ )
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");
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);
670 /*****************************************************************************
671 VCDTracks: initializes area information.
672 Before calling this track information should have been read in.
673 *****************************************************************************/
675 VCDTracks( input_thread_t * p_input )
677 thread_vcd_data_t * p_vcd;
680 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
682 #define area p_input->stream.pp_areas
684 /* We start area addressing for tracks at 1 since the default area 0
685 is reserved for segments */
687 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
689 /* Tracks are Program Chains */
690 input_AddArea( p_input, i, i );
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;
698 /* Current entry being played in track */
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;
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 );
715 /*****************************************************************************
716 VCDLIDs: Reads the LIST IDs from the LOT.
717 *****************************************************************************/
719 VCDLIDs( input_thread_t * p_input )
721 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
723 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
724 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
726 if (vcdinfo_read_psd (p_vcd->vcd)) {
728 vcdinfo_visit_lot (p_vcd->vcd, false);
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.
737 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
738 vcdinfo_visit_lot (p_vcd->vcd, true);
742 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
743 "num LIDs=%d", p_vcd->num_lids);
748 /*****************************************************************************
749 * VCDParse: parse command line
750 *****************************************************************************/
752 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
754 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
759 if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
760 p_itemid->type=VCDINFO_ITEM_TYPE_LID;
763 p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
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;
773 if( !p_input->psz_name )
778 psz_parser = psz_source = strdup( p_input->psz_name );
780 /* Parse input string :
781 * [device][@[type][title]] */
782 while( *psz_parser && *psz_parser != '@' )
787 if( *psz_parser == '@' )
789 /* Found the divide between the source name and the
790 type+entry number. */
797 switch(*psz_parser) {
799 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
803 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
807 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
811 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
818 num = strtol( psz_parser, &psz_next, 10 );
819 if ( *psz_parser != '\0' && *psz_next == '\0')
828 /* No source specified, so figure it out. */
829 if( !p_input->psz_access ) return NULL;
831 psz_source = config_GetPsz( p_input, "vcd" );
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),
839 if (NULL == cd_drives) return NULL;
840 if (cd_drives[0] == NULL) {
841 cdio_free_device_list(cd_drives);
844 psz_source = strdup(cd_drives[0]);
845 cdio_free_device_list(cd_drives);
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);
857 Set's start origin subsequent seeks/reads
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 )
863 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
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;
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 );
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;
879 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
880 "chapter", "Setting entry");
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 )
889 vcdinfo_obj_t *p_vcdobj;
892 if( !psz_dev ) return NULL;
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 );
899 actual_dev=strdup(psz_dev);
900 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
910 /****************************************************************************
911 * VCDReadSector: Read a sector (2324 bytes)
912 ****************************************************************************/
914 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
915 lsn_t cur_lsn, byte_t * p_buffer )
918 uint8_t subheader [8];
919 uint8_t data [M2F2_SECTOR_SIZE];
921 vcdsector_t vcd_sector;
923 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
924 &vcd_sector, cur_lsn, true)
927 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
931 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
936 /****************************************************************************
937 Update the "varname" variable to i_num without triggering a callback.
938 ****************************************************************************/
940 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
941 const char *varname, const char *label)
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 );
949 var_Change( p_input, varname, i_action, &val, NULL );
953 #define meta_info_add_str(title, str) \
955 dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str); \
956 input_AddInfo( p_cat, _(title), "%s", str ); \
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 ); \
963 static void InformationCreate( input_thread_t *p_input )
965 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
966 input_info_category_t *p_cat;
968 p_cat = input_InfoCategory( p_input, "General" );
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));
987 #if FINISHED_PLAYLIST
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,
997 (vcdinfo_get_track_size(p_vcd->vcd, i_track) * 8 * 10000000)
998 / (400 * p_input->stream.control.i_rate) ;
1000 char *config_varname = MODULE_STRING "-title-format";
1002 snprintf(psz_mrl, psz_mrl_max, "%s%s@T%u",
1003 VCD_MRL_PREFIX, psz_source, i_track);
1006 p_title = VCDFormatStr(p_input, p_vcd,
1007 config_GetPsz( p_input, config_varname ),
1013 playlist_AddExt( p_playlist, psz_mrl, p_title, i_duration,
1014 0, 0, playlist_operation, i_pos );
1018 VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1019 const char *psz_source )
1022 playlist_t * p_playlist;
1024 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
1025 strlen("@T") + strlen("100") + 1;
1027 psz_mrl = malloc( psz_mrl_max );
1029 if( psz_mrl == NULL )
1031 msg_Warn( p_input, "out of memory" );
1035 p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1039 msg_Warn( p_input, "can't find playlist" );
1044 if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
1045 /* May fill out more information when the playlist user interface becomes
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);
1053 playlist_Delete( p_playlist, p_playlist->i_index);
1055 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
1057 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, i, psz_mrl,
1058 psz_mrl_max, psz_source, PLAYLIST_APPEND,
1063 playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
1067 vlc_object_release( p_playlist );
1073 /*****************************************************************************
1075 *****************************************************************************/
1077 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
1078 vlc_value_t oldval, vlc_value_t val, void *p_data )
1080 thread_vcd_data_t *p_vcd;
1082 if (NULL == p_vcd_input) return VLC_EGENERIC;
1084 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
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);
1090 p_vcd->i_debug = val.i_int;
1094 /*****************************************************************************
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.
1100 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1101 and VLC_EGENERIC for some other error.
1102 *****************************************************************************/
1104 E_(Open) ( vlc_object_t *p_this )
1106 input_thread_t * p_input = (input_thread_t *)p_this;
1107 thread_vcd_data_t * p_vcd;
1109 vcdinfo_itemid_t itemid;
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;
1117 p_vcd = malloc( sizeof(thread_vcd_data_t) );
1121 LOG_ERR ("out of memory" );
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 );
1129 if ( NULL == psz_source )
1132 return( VLC_EGENERIC );
1135 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
1137 p_vcd->p_segments = NULL;
1138 p_vcd->p_entries = NULL;
1141 p_input->i_mtu = VCD_DATA_ONCE;
1143 vlc_mutex_lock( &p_input->stream.stream_lock );
1145 /* If we are here we can control the pace... */
1146 p_input->stream.b_pace_control = 1;
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;
1152 vlc_mutex_unlock( &p_input->stream.stream_lock );
1154 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1156 msg_Warn( p_input, "could not open %s", psz_source );
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)
1170 vcdinfo_close( p_vcd->vcd );
1174 /* Set stream and area data */
1175 vlc_mutex_lock( &p_input->stream.stream_lock );
1177 /* Initialize ES structures */
1178 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1180 /* disc input method */
1181 p_input->stream.i_method = INPUT_METHOD_VCD;
1183 p_input->stream.i_area_nb = 1;
1186 /* Initialize segment information. */
1187 VCDSegments( p_input );
1189 /* Initialize track area information. */
1190 VCDTracks( p_input );
1192 if( VCDEntryPoints( p_input ) < 0 )
1194 msg_Warn( p_input, "could not read entry points, will not use them" );
1195 p_vcd->b_valid_ep = false;
1198 if( VCDLIDs( p_input ) < 0 )
1200 msg_Warn( p_input, "could not read entry LIDs" );
1203 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1205 vlc_mutex_unlock( &p_input->stream.stream_lock );
1207 if ( ! b_play_ok ) {
1208 vcdinfo_close( p_vcd->vcd );
1212 if( !p_input->psz_demux || !*p_input->psz_demux )
1215 p_input->psz_demux = "vcdx";
1217 p_input->psz_demux = "ps";
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 );
1225 InformationCreate( p_input );
1227 #if FINISHED_PLAYLIST
1228 VCDFixupPlayList( p_input, p_vcd, psz_source );
1237 return VLC_EGENERIC;
1240 /*****************************************************************************
1241 * Close: closes VCD releasing allocated memory.
1242 *****************************************************************************/
1244 E_(Close) ( vlc_object_t *p_this )
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;
1249 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1250 vcdinfo_close( p_vcd->vcd );
1252 free( p_vcd->p_entries );
1253 free( p_vcd->p_segments );
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.
1259 if( p_vcd->p_intf != NULL )
1261 p_vcd->p_intf = NULL;
1265 p_input->p_access_data = NULL;