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.7 2003/12/03 21:55:33 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>
33 #include <vlc_interface.h>
35 #include "../../demux/mpeg/system.h"
38 #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 /*****************************************************************************
55 *****************************************************************************/
57 /* First those which are accessed from outside (via pointers). */
58 static int VCDRead ( input_thread_t *, byte_t *, size_t );
59 static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
61 /* Now those which are strictly internal */
62 static void VCDSetOrigin ( input_thread_t *, lsn_t origin_lsn,
63 lsn_t cur_lsn, lsn_t end_lsn,
64 int cur_entry, track_t track );
65 static int VCDEntryPoints ( input_thread_t * );
66 static int VCDLIDs ( input_thread_t * );
67 static int VCDSegments ( input_thread_t * );
68 static void VCDTracks ( input_thread_t * );
69 static int VCDReadSector ( vlc_object_t *p_this,
70 const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn,
72 static char *VCDParse ( input_thread_t *,
73 /*out*/ vcdinfo_itemid_t * p_itemid );
75 static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
76 const char *varname, const char *label );
78 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
80 /****************************************************************************
82 ****************************************************************************/
84 /* FIXME: This variable is a hack. Would be nice to eliminate the
87 static input_thread_t *p_vcd_input = NULL;
89 /* process messages that originate from libcdio. */
91 cdio_log_handler (cdio_log_level_t level, const char message[])
93 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
97 if (p_vcd->i_debug & INPUT_DBG_CDIO)
98 msg_Dbg( p_vcd_input, message);
101 msg_Warn( p_vcd_input, message);
104 case CDIO_LOG_ASSERT:
105 msg_Err( p_vcd_input, message);
108 msg_Warn( p_vcd_input, message,
109 _("The above message had unknown log level"),
115 /* process messages that originate from vcdinfo. */
117 vcd_log_handler (vcd_log_level_t level, const char message[])
119 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
123 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
124 msg_Dbg( p_vcd_input, message);
127 msg_Warn( p_vcd_input, message);
131 msg_Err( p_vcd_input, message);
134 msg_Warn( p_vcd_input, "%s\n%s %d", message,
135 _("The above message had unknown vcdimager log level"),
141 /*****************************************************************************
142 * VCDRead: reads i_len bytes from the VCD into p_buffer.
143 *****************************************************************************
144 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
146 *****************************************************************************/
148 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
150 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
154 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
158 dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn );
160 /* Compute the number of blocks we have to read */
162 i_blocks = i_len / M2F2_SECTOR_SIZE;
164 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
167 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
168 vcdplayer_read_status_t read_status;
170 /* We've run off of the end of this entry. Do we continue or stop? */
171 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
172 "end reached, cur: %u", p_vcd->cur_lsn );
174 read_status = vcdplayer_pbc_is_on( p_vcd )
175 ? vcdplayer_pbc_nav( p_input )
176 : vcdplayer_non_pbc_nav( p_input );
178 switch (read_status) {
180 /* End reached. Return NULL to indicated this. */
182 /* Some sort of error. */
185 case READ_STILL_FRAME:
187 /* Reached the end of a still frame. */
189 byte_t * p_buf = p_buffer;
190 pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
192 p_buf += (i_index*M2F2_SECTOR_SIZE);
193 memset(p_buf, 0, M2F2_SECTOR_SIZE);
196 dbg_print(INPUT_DBG_STILL, "Handled still event\n");
198 /* p_vcd->p_intf->b_end_of_cell = true; */
199 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
201 vlc_mutex_lock( &p_input->stream.stream_lock );
203 p_pgrm = p_input->stream.p_selected_program;
204 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
206 vlc_mutex_unlock( &p_input->stream.stream_lock );
208 input_ClockManageControl( p_input, p_pgrm, 0 );
210 return i_read + M2F2_SECTOR_SIZE;
218 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
220 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
222 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
229 if( p_vcd->b_valid_ep &&
230 /* FIXME kludge so that read does not update chapter
231 * when a manual chapter change was requested and not
232 * yet accomplished */
233 !p_input->stream.p_new_area )
235 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
237 vlc_mutex_lock( &p_input->stream.stream_lock );
239 if( i_entry < p_vcd->num_entries &&
240 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
242 dbg_print( INPUT_DBG_PBC,
243 "new entry, i_entry %d, sector %d, es %d",
244 i_entry, p_vcd->cur_lsn,
245 p_vcd->p_entries[i_entry] );
246 p_vcd->play_item.num =
247 ++ p_input->stream.p_selected_area->i_part;
248 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
249 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
250 "chapter", "Setting entry" );
252 vlc_mutex_unlock( &p_input->stream.stream_lock );
255 i_read += M2F2_SECTOR_SIZE;
258 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
260 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
261 p_vcd->cur_lsn, p_last_sector ) < 0 )
263 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
267 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
268 p_last_sector, i_len % M2F2_SECTOR_SIZE );
269 i_read += i_len % M2F2_SECTOR_SIZE;
276 /*****************************************************************************
277 * VCDSetProgram: Does nothing since a VCD is mono_program
278 *****************************************************************************/
280 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
282 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
283 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
288 /*****************************************************************************
289 * VCDSetArea: initialize internal data structures and input stream data
290 so set subsequent reading and seeking to reflect that we are
291 at track x, entry or segment y.
292 This is called for each user navigation request, e.g. the GUI
293 Chapter/Title selections or in initial MRL parsing.
294 ****************************************************************************/
296 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
298 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
299 unsigned int i_entry = p_area->i_part;
300 track_t i_track = p_area->i_id;
301 int old_seekable = p_input->stream.b_seekable;
302 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
304 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
305 "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
306 i_track, i_entry, old_seekable,
307 (long unsigned int) p_area,
308 (long unsigned int) p_input->stream.p_selected_area );
310 /* we can't use the interface slider until initilization is complete */
311 p_input->stream.b_seekable = 0;
313 if( p_area != p_input->stream.p_selected_area )
317 /* If is the result of a track change, make the entry valid. */
318 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
319 i_entry = p_area->i_plugin_data;
321 /* Change the default area */
322 p_input->stream.p_selected_area = p_area;
324 /* Update the navigation variables without triggering a callback */
325 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
328 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
329 for( i = p_area->i_plugin_data; i < i_nb; i++ )
331 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
332 "chapter", "Adding entry choice");
337 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
338 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
341 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
342 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
343 p_vcd->p_sectors[i_track+1],
346 p_input->stream.b_seekable = old_seekable;
347 /* warn interface that something has changed */
348 p_input->stream.b_changed = 1;
354 /****************************************************************************
356 ****************************************************************************/
358 VCDSeek( input_thread_t * p_input, off_t i_off )
360 thread_vcd_data_t * p_vcd;
361 unsigned int i_entry=0; /* invalid entry */
363 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
365 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
367 vlc_mutex_lock( &p_input->stream.stream_lock );
368 #define p_area p_input->stream.p_selected_area
370 if( p_vcd->b_valid_ep )
372 for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
374 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
376 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
377 "chapter", "Setting entry" );
381 p_vcd->play_item.num = p_area->i_part = i_entry;
382 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
386 p_input->stream.p_selected_area->i_tell = i_off;
388 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
389 "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
390 p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
391 p_input->stream.p_selected_area->i_start, i_entry );
393 vlc_mutex_unlock( &p_input->stream.stream_lock );
396 /*****************************************************************************
397 VCDPlay: set up internal structures so seeking/reading places an item.
398 itemid: the thing to play.
399 user_entry: true if itemid is a user selection (rather than internally-
400 generated selection such as via PBC) in which case we may have to adjust
401 for differences in numbering.
402 *****************************************************************************/
404 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
406 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
407 input_area_t * p_area;
411 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
412 itemid.num, itemid.type);
414 #define area p_input->stream.pp_areas
416 switch (itemid.type) {
417 case VCDINFO_ITEM_TYPE_TRACK:
419 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
422 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
423 LOG_ERR ("Invalid track number %d", itemid.num );
426 p_area = area[itemid.num];
427 p_area->i_part = p_area->i_plugin_data;
428 p_input->stream.b_seekable = 1;
430 case VCDINFO_ITEM_TYPE_SEGMENT:
431 /* Valid segments go from 0...num_segments-1. */
432 if (itemid.num >= p_vcd->num_segments) {
433 LOG_ERR ( "Invalid segment number: %d", itemid.num );
436 vcdinfo_video_segment_type_t segtype =
437 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
439 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
440 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
441 (int) segtype, itemid.num);
444 p_area->i_part = itemid.num;
448 case VCDINFO_FILES_VIDEO_NTSC_STILL:
449 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
450 case VCDINFO_FILES_VIDEO_PAL_STILL:
451 case VCDINFO_FILES_VIDEO_PAL_STILL2:
452 p_input->stream.b_seekable = 0;
453 p_vcd->in_still = -5;
456 p_input->stream.b_seekable = 1;
462 case VCDINFO_ITEM_TYPE_LID:
463 /* LIDs go from 1..num_lids. */
464 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
465 LOG_ERR ( "Invalid LID number: %d", itemid.num );
468 p_vcd->cur_lid = itemid.num;
469 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
471 switch (p_vcd->pxd.descriptor_type) {
473 case PSD_TYPE_SELECTION_LIST:
474 case PSD_TYPE_EXT_SELECTION_LIST: {
475 vcdinfo_itemid_t trans_itemid;
476 uint16_t trans_itemid_num;
478 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
479 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
480 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
481 p_vcd->loop_count = 1;
482 p_vcd->loop_item = trans_itemid;
483 return VCDPlay( p_input, trans_itemid );
487 case PSD_TYPE_PLAY_LIST: {
488 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
490 return vcdplayer_inc_play_item(p_input)
491 ? VLC_SUCCESS : VLC_EGENERIC;
495 case PSD_TYPE_END_LIST:
496 case PSD_TYPE_COMMAND_LIST:
503 case VCDINFO_ITEM_TYPE_ENTRY:
504 /* Entries go from 0..num_entries-1. */
505 if (itemid.num >= p_vcd->num_entries) {
506 LOG_ERR ("Invalid entry number: %d", itemid.num );
509 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
510 p_area = area[cur_track];
511 p_area->i_part = itemid.num;
512 p_input->stream.b_seekable = 1;
516 LOG_ERR ("unknown entry type" );
520 VCDSetArea( p_input, p_area );
524 p_vcd->play_item = itemid;
526 dbg_print( (INPUT_DBG_CALL),
527 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
528 p_area->i_start, p_area->i_size,
529 p_area->i_tell, p_vcd->cur_lsn );
534 /*****************************************************************************
535 VCDEntryPoints: Reads the information about the entry points on the disc
536 and initializes area information with that.
537 Before calling this track information should have been read in.
538 *****************************************************************************/
540 VCDEntryPoints( input_thread_t * p_input )
542 thread_vcd_data_t * p_vcd;
544 unsigned int i, i_entry_index = 0;
545 unsigned int i_previous_track = CDIO_INVALID_TRACK;
547 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
549 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
553 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
555 if( p_vcd->p_entries == NULL )
557 LOG_ERR ("not enough memory for entry points treatment" );
561 p_vcd->num_entries = 0;
563 for( i = 0 ; i < i_nb ; i++ )
565 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
566 if( i_track <= p_input->stream.i_area_nb )
568 p_vcd->p_entries[i] =
569 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
570 p_input->stream.pp_areas[i_track]->i_part_nb ++;
572 /* if this entry belongs to a new track */
573 if( i_track != i_previous_track )
575 /* i_plugin_data is used to store the first entry of the area*/
576 p_input->stream.pp_areas[i_track]->i_plugin_data =
578 i_previous_track = i_track;
579 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
582 p_vcd->num_entries ++;
585 msg_Warn( p_input, "wrong track number found in entry points" );
587 p_vcd->b_valid_ep = true;
591 /*****************************************************************************
592 * VCDSegments: Reads the information about the segments the disc.
593 *****************************************************************************/
595 VCDSegments( input_thread_t * p_input )
597 thread_vcd_data_t * p_vcd;
599 unsigned int num_segments;
602 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
603 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
605 #define area p_input->stream.pp_areas
607 /* area 0 is reserved for segments. Set Absolute start offset
609 area[0]->i_plugin_data = 0;
610 input_DelArea( p_input, area[0] );
611 input_AddArea( p_input, 0, 0 );
613 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
614 * (off_t)M2F2_SECTOR_SIZE;
615 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
616 * (off_t)M2F2_SECTOR_SIZE;
618 /* Default Segment */
621 /* i_plugin_data is used to store which entry point is the first
622 of the track (area) */
623 area[0]->i_plugin_data = 0;
625 area[0]->i_part_nb = 0;
627 dbg_print( INPUT_DBG_MRL,
628 "area[0] id: %d, i_start: %lld, i_size: %lld",
629 area[0]->i_id, area[0]->i_start, area[0]->i_size );
631 if (num_segments == 0) return 0;
633 /* We have one additional segment allocated so we can get the size
634 by subtracting seg[i+1] - seg[i].
636 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
637 if( p_vcd->p_segments == NULL )
639 LOG_ERR ("not enough memory for segment treatment" );
643 /* Update the navigation variables without triggering a callback */
644 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
645 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
647 for( i = 0 ; i < num_segments ; i++ )
649 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
650 area[0]->i_part_nb ++;
651 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
652 "chapter", "Adding segment choice");
657 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
658 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
663 /*****************************************************************************
664 VCDTracks: initializes area information.
665 Before calling this track information should have been read in.
666 *****************************************************************************/
668 VCDTracks( input_thread_t * p_input )
670 thread_vcd_data_t * p_vcd;
673 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
675 #define area p_input->stream.pp_areas
677 /* We start area addressing for tracks at 1 since the default area 0
678 is reserved for segments */
680 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
682 /* Tracks are Program Chains */
683 input_AddArea( p_input, i, i );
685 /* Absolute start byte offset and byte size */
686 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
687 * (off_t)M2F2_SECTOR_SIZE;
688 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
689 * (off_t)M2F2_SECTOR_SIZE;
691 /* Current entry being played in track */
694 /* i_plugin_data is used to store which entry point is the first
695 * of the track (area) */
696 area[i]->i_plugin_data = 0;
698 dbg_print( INPUT_DBG_MRL,
699 "area[%d] id: %d, i_start: %lld, i_size: %lld",
700 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
708 /*****************************************************************************
709 VCDLIDs: Reads the LIST IDs from the LOT.
710 *****************************************************************************/
712 VCDLIDs( input_thread_t * p_input )
714 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
716 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
717 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
719 if (vcdinfo_read_psd (p_vcd->vcd)) {
721 vcdinfo_visit_lot (p_vcd->vcd, false);
725 We need to change libvcdinfo to be more robust when there are
726 problems reading the extended PSD. Given that area-highlighting and
727 selection features in the extended PSD haven't been implemented,
728 it's best then to not try to read this at all.
730 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
731 vcdinfo_visit_lot (p_vcd->vcd, true);
735 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
736 "num LIDs=%d", p_vcd->num_lids);
741 /*****************************************************************************
742 * VCDParse: parse command line
743 *****************************************************************************/
745 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
747 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
752 if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
753 p_itemid->type=VCDINFO_ITEM_TYPE_LID;
756 p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
761 /* On Win32 we want the VCD access plugin to be explicitly requested,
762 * we end up with lots of problems otherwise */
763 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
766 if( !p_input->psz_name )
771 psz_parser = psz_source = strdup( p_input->psz_name );
773 /* Parse input string :
774 * [device][@[type][title]] */
775 while( *psz_parser && *psz_parser != '@' )
780 if( *psz_parser == '@' )
782 /* Found the divide between the source name and the
783 type+entry number. */
790 switch(*psz_parser) {
792 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
796 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
800 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
804 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
811 num = strtol( psz_parser, &psz_next, 10 );
812 if ( *psz_parser != '\0' && *psz_next == '\0')
821 /* No source specified, so figure it out. */
822 if( !p_input->psz_access ) return NULL;
824 psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
826 if( !psz_source || 0==strlen(psz_source) ) {
827 /* Scan for a CD-ROM drive with a VCD in it. */
828 char **cd_drives = cdio_get_devices_with_cap(NULL,
829 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
830 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
832 if (NULL == cd_drives) return NULL;
833 if (cd_drives[0] == NULL) {
834 cdio_free_device_list(cd_drives);
837 psz_source = strdup(cd_drives[0]);
838 cdio_free_device_list(cd_drives);
842 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
843 "source=%s entry=%d type=%d",
844 psz_source, p_itemid->num, p_itemid->type);
850 Set's start origin subsequent seeks/reads
853 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
854 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
856 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
858 p_vcd->origin_lsn = origin_lsn;
859 p_vcd->cur_lsn = cur_lsn;
860 p_vcd->end_lsn = end_lsn;
861 p_vcd->cur_track = cur_track;
862 p_vcd->play_item.num = cur_entry;
863 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
865 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
866 "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
867 origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
869 p_input->stream.p_selected_area->i_tell =
870 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
872 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
873 "chapter", "Setting entry");
876 /*****************************************************************************
877 * vcd_Open: Opens a VCD device or file and returns an opaque handle
878 *****************************************************************************/
879 static vcdinfo_obj_t *
880 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
882 vcdinfo_obj_t *p_vcdobj;
885 if( !psz_dev ) return NULL;
887 /* Set where to log errors messages from libcdio. */
888 p_vcd_input = (input_thread_t *)p_this;
889 cdio_log_set_handler ( cdio_log_handler );
890 vcd_log_set_handler ( vcd_log_handler );
892 actual_dev=strdup(psz_dev);
893 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
903 /****************************************************************************
904 * VCDReadSector: Read a sector (2324 bytes)
905 ****************************************************************************/
907 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
908 lsn_t cur_lsn, byte_t * p_buffer )
911 uint8_t subheader [8];
912 uint8_t data [M2F2_SECTOR_SIZE];
914 vcdsector_t vcd_sector;
916 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
917 &vcd_sector, cur_lsn, true)
920 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
924 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
929 /****************************************************************************
930 Update the "varname" variable to i_num without triggering a callback.
931 ****************************************************************************/
933 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
934 const char *varname, const char *label)
938 if (NULL != p_vcd_input) {
939 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
940 dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
942 var_Change( p_input, varname, i_action, &val, NULL );
946 #define meta_info_add_str(title, str) \
948 dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str); \
949 input_AddInfo( p_cat, _(title), "%s", str ); \
952 #define meta_info_add_num(title, num) \
953 dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num); \
954 input_AddInfo( p_cat, _(title), "%d", num ); \
956 static void InformationCreate( input_thread_t *p_input )
958 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
959 input_info_category_t *p_cat;
961 p_cat = input_InfoCategory( p_input, "General" );
963 meta_info_add_str( "VCD Format", vcdinfo_get_format_version_str(p_vcd->vcd));
964 meta_info_add_str( "Album", vcdinfo_get_album_id(p_vcd->vcd));
965 meta_info_add_str( "Application",vcdinfo_get_application_id(p_vcd->vcd));
966 meta_info_add_str( "Preparer", vcdinfo_get_preparer_id(p_vcd->vcd));
967 meta_info_add_num( "Vol #", vcdinfo_get_volume_num(p_vcd->vcd));
968 meta_info_add_num( "Vol max #", vcdinfo_get_volume_count(p_vcd->vcd));
969 meta_info_add_str( "Volume Set", vcdinfo_get_volumeset_id(p_vcd->vcd));
970 meta_info_add_str( "Volume", vcdinfo_get_volume_id(p_vcd->vcd));
971 meta_info_add_str( "Publisher", vcdinfo_get_publisher_id(p_vcd->vcd));
972 meta_info_add_str( "System Id", vcdinfo_get_system_id(p_vcd->vcd));
973 meta_info_add_num( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd));
974 meta_info_add_num( "Entries", vcdinfo_get_num_entries(p_vcd->vcd));
975 meta_info_add_num( "Segments", vcdinfo_get_num_segments(p_vcd->vcd));
976 meta_info_add_num( "Tracks", vcdinfo_get_num_tracks(p_vcd->vcd));
980 /*****************************************************************************
982 *****************************************************************************/
984 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
985 vlc_value_t oldval, vlc_value_t val, void *p_data )
987 thread_vcd_data_t *p_vcd;
989 if (NULL == p_vcd_input) return VLC_EGENERIC;
991 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
993 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
994 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
995 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
997 p_vcd->i_debug = val.i_int;
1001 /*****************************************************************************
1003 read in meta-information about VCD: the number of tracks, segments,
1004 entries, size and starting information. Then set up state variables so
1005 that we read/seek starting at the location specified.
1007 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1008 and VLC_EGENERIC for some other error.
1009 *****************************************************************************/
1011 E_(Open) ( vlc_object_t *p_this )
1013 input_thread_t * p_input = (input_thread_t *)p_this;
1014 thread_vcd_data_t * p_vcd;
1016 vcdinfo_itemid_t itemid;
1019 p_input->pf_read = VCDRead;
1020 p_input->pf_seek = VCDSeek;
1021 p_input->pf_set_area = VCDSetArea;
1022 p_input->pf_set_program = VCDSetProgram;
1024 p_vcd = malloc( sizeof(thread_vcd_data_t) );
1028 LOG_ERR ("out of memory" );
1032 p_input->p_access_data = (void *)p_vcd;
1033 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1034 psz_source = VCDParse( p_input, &itemid );
1036 if ( NULL == psz_source )
1039 return( VLC_EGENERIC );
1042 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
1044 p_vcd->p_segments = NULL;
1045 p_vcd->p_entries = NULL;
1048 p_input->i_mtu = VCD_DATA_ONCE;
1050 vlc_mutex_lock( &p_input->stream.stream_lock );
1052 /* If we are here we can control the pace... */
1053 p_input->stream.b_pace_control = 1;
1055 p_input->stream.b_seekable = 1;
1056 p_input->stream.p_selected_area->i_size = 0;
1057 p_input->stream.p_selected_area->i_tell = 0;
1059 vlc_mutex_unlock( &p_input->stream.stream_lock );
1061 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1063 msg_Warn( p_input, "could not open %s", psz_source );
1066 return VLC_EGENERIC;
1069 /* Get track information. */
1070 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
1071 vcdinfo_get_cd_image(p_vcd->vcd),
1072 &p_vcd->p_sectors );
1074 if( p_vcd->num_tracks < 0 )
1075 LOG_ERR ("unable to count tracks" );
1076 else if( p_vcd->num_tracks <= 1 )
1077 LOG_ERR ("no movie tracks found" );
1078 if( p_vcd->num_tracks <= 1)
1080 vcdinfo_close( p_vcd->vcd );
1082 return VLC_EGENERIC;
1085 /* Set stream and area data */
1086 vlc_mutex_lock( &p_input->stream.stream_lock );
1088 /* Initialize ES structures */
1089 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1091 /* disc input method */
1092 p_input->stream.i_method = INPUT_METHOD_VCD;
1094 p_input->stream.i_area_nb = 1;
1097 /* Initialize segment information. */
1098 VCDSegments( p_input );
1100 /* Initialize track area information. */
1101 VCDTracks( p_input );
1103 if( VCDEntryPoints( p_input ) < 0 )
1105 msg_Warn( p_input, "could not read entry points, will not use them" );
1106 p_vcd->b_valid_ep = false;
1109 if( VCDLIDs( p_input ) < 0 )
1111 msg_Warn( p_input, "could not read entry LIDs" );
1114 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1116 vlc_mutex_unlock( &p_input->stream.stream_lock );
1118 if ( ! b_play_ok ) {
1119 vcdinfo_close( p_vcd->vcd );
1121 return VLC_EGENERIC;
1124 if( !p_input->psz_demux || !*p_input->psz_demux )
1127 p_input->psz_demux = "vcdx";
1129 p_input->psz_demux = "ps";
1133 p_vcd->p_intf = intf_Create( p_input, "vcdx" );
1134 p_vcd->p_intf->b_block = VLC_FALSE;
1135 intf_RunThread( p_vcd->p_intf );
1137 InformationCreate( p_input );
1142 /*****************************************************************************
1143 * Close: closes VCD releasing allocated memory.
1144 *****************************************************************************/
1146 E_(Close) ( vlc_object_t *p_this )
1148 input_thread_t * p_input = (input_thread_t *)p_this;
1149 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1151 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1152 vcdinfo_close( p_vcd->vcd );
1154 free( p_vcd->p_entries );
1155 free( p_vcd->p_segments );
1157 /* For reasons that are a mystery to me we don't have to deal with
1158 stopping, and destroying the p_vcd->p_intf thread. And if we do
1159 it causes problems upstream.
1161 if( p_vcd->p_intf != NULL )
1163 p_vcd->p_intf = NULL;
1167 p_input->p_access_data = NULL;