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.9 2003/12/05 05:01:17 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");
200 p_vcd->p_intf->p_sys->b_still = 1;
201 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
203 vlc_mutex_lock( &p_input->stream.stream_lock );
205 p_pgrm = p_input->stream.p_selected_program;
206 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
208 vlc_mutex_unlock( &p_input->stream.stream_lock );
210 dbg_print(INPUT_DBG_STILL, "Clock manage");
211 input_ClockManageControl( p_input, p_pgrm, 0 );
212 dbg_print(INPUT_DBG_STILL, "Clock manage done");
214 return i_read + M2F2_SECTOR_SIZE;
222 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
224 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
226 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
233 if( p_vcd->b_valid_ep &&
234 /* FIXME kludge so that read does not update chapter
235 * when a manual chapter change was requested and not
236 * yet accomplished */
237 !p_input->stream.p_new_area )
239 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
241 vlc_mutex_lock( &p_input->stream.stream_lock );
243 if( i_entry < p_vcd->num_entries &&
244 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
246 dbg_print( INPUT_DBG_PBC,
247 "new entry, i_entry %d, sector %d, es %d",
248 i_entry, p_vcd->cur_lsn,
249 p_vcd->p_entries[i_entry] );
250 p_vcd->play_item.num =
251 ++ p_input->stream.p_selected_area->i_part;
252 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
253 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
254 "chapter", "Setting entry" );
256 vlc_mutex_unlock( &p_input->stream.stream_lock );
259 i_read += M2F2_SECTOR_SIZE;
262 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
264 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
265 p_vcd->cur_lsn, p_last_sector ) < 0 )
267 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
271 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
272 p_last_sector, i_len % M2F2_SECTOR_SIZE );
273 i_read += i_len % M2F2_SECTOR_SIZE;
280 /*****************************************************************************
281 * VCDSetProgram: Does nothing since a VCD is mono_program
282 *****************************************************************************/
284 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
286 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
287 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
292 /*****************************************************************************
293 * VCDSetArea: initialize internal data structures and input stream data
294 so set subsequent reading and seeking to reflect that we are
295 at track x, entry or segment y.
296 This is called for each user navigation request, e.g. the GUI
297 Chapter/Title selections or in initial MRL parsing.
298 ****************************************************************************/
300 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
302 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
303 unsigned int i_entry = p_area->i_part;
304 track_t i_track = p_area->i_id;
305 int old_seekable = p_input->stream.b_seekable;
306 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
308 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
309 "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
310 i_track, i_entry, old_seekable,
311 (long unsigned int) p_area,
312 (long unsigned int) p_input->stream.p_selected_area );
314 /* we can't use the interface slider until initilization is complete */
315 p_input->stream.b_seekable = 0;
317 if( p_area != p_input->stream.p_selected_area )
321 /* If is the result of a track change, make the entry valid. */
322 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
323 i_entry = p_area->i_plugin_data;
325 /* Change the default area */
326 p_input->stream.p_selected_area = p_area;
328 /* Update the navigation variables without triggering a callback */
329 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
332 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
333 for( i = p_area->i_plugin_data; i < i_nb; i++ )
335 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
336 "chapter", "Adding entry choice");
341 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
342 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
345 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
346 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
347 p_vcd->p_sectors[i_track+1],
350 p_input->stream.b_seekable = old_seekable;
351 /* warn interface that something has changed */
352 p_input->stream.b_changed = 1;
358 /****************************************************************************
360 ****************************************************************************/
362 VCDSeek( input_thread_t * p_input, off_t i_off )
364 thread_vcd_data_t * p_vcd;
365 unsigned int i_entry=0; /* invalid entry */
367 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
369 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
371 vlc_mutex_lock( &p_input->stream.stream_lock );
372 #define p_area p_input->stream.p_selected_area
374 if( p_vcd->b_valid_ep )
376 for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
378 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
380 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
381 "chapter", "Setting entry" );
385 p_vcd->play_item.num = p_area->i_part = i_entry;
386 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
390 p_input->stream.p_selected_area->i_tell = i_off;
392 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
393 "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
394 p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
395 p_input->stream.p_selected_area->i_start, i_entry );
397 vlc_mutex_unlock( &p_input->stream.stream_lock );
400 /*****************************************************************************
401 VCDPlay: set up internal structures so seeking/reading places an item.
402 itemid: the thing to play.
403 user_entry: true if itemid is a user selection (rather than internally-
404 generated selection such as via PBC) in which case we may have to adjust
405 for differences in numbering.
406 *****************************************************************************/
408 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
410 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
411 input_area_t * p_area;
413 p_vcd->in_still = false;
415 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
416 itemid.num, itemid.type);
418 #define area p_input->stream.pp_areas
420 switch (itemid.type) {
421 case VCDINFO_ITEM_TYPE_TRACK:
423 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
426 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
427 LOG_ERR ("Invalid track number %d", itemid.num );
430 p_area = area[itemid.num];
431 p_area->i_part = p_area->i_plugin_data;
432 p_input->stream.b_seekable = 1;
434 case VCDINFO_ITEM_TYPE_SEGMENT:
435 /* Valid segments go from 0...num_segments-1. */
436 if (itemid.num >= p_vcd->num_segments) {
437 LOG_ERR ( "Invalid segment number: %d", itemid.num );
440 vcdinfo_video_segment_type_t segtype =
441 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
443 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
444 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
445 (int) segtype, itemid.num);
448 p_area->i_part = itemid.num;
452 case VCDINFO_FILES_VIDEO_NTSC_STILL:
453 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
454 case VCDINFO_FILES_VIDEO_PAL_STILL:
455 case VCDINFO_FILES_VIDEO_PAL_STILL2:
456 p_input->stream.b_seekable = 0;
457 p_vcd->in_still = true;
460 p_input->stream.b_seekable = 1;
461 p_vcd->in_still = false;
466 case VCDINFO_ITEM_TYPE_LID:
467 /* LIDs go from 1..num_lids. */
468 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
469 LOG_ERR ( "Invalid LID number: %d", itemid.num );
472 p_vcd->cur_lid = itemid.num;
473 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
475 switch (p_vcd->pxd.descriptor_type) {
477 case PSD_TYPE_SELECTION_LIST:
478 case PSD_TYPE_EXT_SELECTION_LIST: {
479 vcdinfo_itemid_t trans_itemid;
480 uint16_t trans_itemid_num;
482 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
483 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
484 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
485 p_vcd->loop_count = 1;
486 p_vcd->loop_item = trans_itemid;
487 return VCDPlay( p_input, trans_itemid );
491 case PSD_TYPE_PLAY_LIST: {
492 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
494 return vcdplayer_inc_play_item(p_input)
495 ? VLC_SUCCESS : VLC_EGENERIC;
499 case PSD_TYPE_END_LIST:
500 case PSD_TYPE_COMMAND_LIST:
507 case VCDINFO_ITEM_TYPE_ENTRY:
508 /* Entries go from 0..num_entries-1. */
509 if (itemid.num >= p_vcd->num_entries) {
510 LOG_ERR ("Invalid entry number: %d", itemid.num );
513 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
514 p_area = area[cur_track];
515 p_area->i_part = itemid.num;
516 p_input->stream.b_seekable = 1;
520 LOG_ERR ("unknown entry type" );
524 VCDSetArea( p_input, p_area );
528 p_vcd->play_item = itemid;
530 dbg_print( (INPUT_DBG_CALL),
531 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
532 p_area->i_start, p_area->i_size,
533 p_area->i_tell, p_vcd->cur_lsn );
538 /*****************************************************************************
539 VCDEntryPoints: Reads the information about the entry points on the disc
540 and initializes area information with that.
541 Before calling this track information should have been read in.
542 *****************************************************************************/
544 VCDEntryPoints( input_thread_t * p_input )
546 thread_vcd_data_t * p_vcd;
548 unsigned int i, i_entry_index = 0;
549 unsigned int i_previous_track = CDIO_INVALID_TRACK;
551 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
553 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
557 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
559 if( p_vcd->p_entries == NULL )
561 LOG_ERR ("not enough memory for entry points treatment" );
565 p_vcd->num_entries = 0;
567 for( i = 0 ; i < i_nb ; i++ )
569 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
570 if( i_track <= p_input->stream.i_area_nb )
572 p_vcd->p_entries[i] =
573 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
574 p_input->stream.pp_areas[i_track]->i_part_nb ++;
576 /* if this entry belongs to a new track */
577 if( i_track != i_previous_track )
579 /* i_plugin_data is used to store the first entry of the area*/
580 p_input->stream.pp_areas[i_track]->i_plugin_data =
582 i_previous_track = i_track;
583 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
586 p_vcd->num_entries ++;
589 msg_Warn( p_input, "wrong track number found in entry points" );
591 p_vcd->b_valid_ep = true;
595 /*****************************************************************************
596 * VCDSegments: Reads the information about the segments the disc.
597 *****************************************************************************/
599 VCDSegments( input_thread_t * p_input )
601 thread_vcd_data_t * p_vcd;
603 unsigned int num_segments;
606 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
607 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
609 #define area p_input->stream.pp_areas
611 /* area 0 is reserved for segments. Set Absolute start offset
613 area[0]->i_plugin_data = 0;
614 input_DelArea( p_input, area[0] );
615 input_AddArea( p_input, 0, 0 );
617 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
618 * (off_t)M2F2_SECTOR_SIZE;
619 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
620 * (off_t)M2F2_SECTOR_SIZE;
622 /* Default Segment */
625 /* i_plugin_data is used to store which entry point is the first
626 of the track (area) */
627 area[0]->i_plugin_data = 0;
629 area[0]->i_part_nb = 0;
631 dbg_print( INPUT_DBG_MRL,
632 "area[0] id: %d, i_start: %lld, i_size: %lld",
633 area[0]->i_id, area[0]->i_start, area[0]->i_size );
635 if (num_segments == 0) return 0;
637 /* We have one additional segment allocated so we can get the size
638 by subtracting seg[i+1] - seg[i].
640 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
641 if( p_vcd->p_segments == NULL )
643 LOG_ERR ("not enough memory for segment treatment" );
647 /* Update the navigation variables without triggering a callback */
648 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
649 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
651 for( i = 0 ; i < num_segments ; i++ )
653 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
654 area[0]->i_part_nb ++;
655 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
656 "chapter", "Adding segment choice");
661 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
662 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
667 /*****************************************************************************
668 VCDTracks: initializes area information.
669 Before calling this track information should have been read in.
670 *****************************************************************************/
672 VCDTracks( input_thread_t * p_input )
674 thread_vcd_data_t * p_vcd;
677 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
679 #define area p_input->stream.pp_areas
681 /* We start area addressing for tracks at 1 since the default area 0
682 is reserved for segments */
684 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
686 /* Tracks are Program Chains */
687 input_AddArea( p_input, i, i );
689 /* Absolute start byte offset and byte size */
690 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
691 * (off_t)M2F2_SECTOR_SIZE;
692 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
693 * (off_t)M2F2_SECTOR_SIZE;
695 /* Current entry being played in track */
698 /* i_plugin_data is used to store which entry point is the first
699 * of the track (area) */
700 area[i]->i_plugin_data = 0;
702 dbg_print( INPUT_DBG_MRL,
703 "area[%d] id: %d, i_start: %lld, i_size: %lld",
704 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
712 /*****************************************************************************
713 VCDLIDs: Reads the LIST IDs from the LOT.
714 *****************************************************************************/
716 VCDLIDs( input_thread_t * p_input )
718 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
720 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
721 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
723 if (vcdinfo_read_psd (p_vcd->vcd)) {
725 vcdinfo_visit_lot (p_vcd->vcd, false);
729 We need to change libvcdinfo to be more robust when there are
730 problems reading the extended PSD. Given that area-highlighting and
731 selection features in the extended PSD haven't been implemented,
732 it's best then to not try to read this at all.
734 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
735 vcdinfo_visit_lot (p_vcd->vcd, true);
739 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
740 "num LIDs=%d", p_vcd->num_lids);
745 /*****************************************************************************
746 * VCDParse: parse command line
747 *****************************************************************************/
749 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
751 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
756 if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
757 p_itemid->type=VCDINFO_ITEM_TYPE_LID;
760 p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
765 /* On Win32 we want the VCD access plugin to be explicitly requested,
766 * we end up with lots of problems otherwise */
767 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
770 if( !p_input->psz_name )
775 psz_parser = psz_source = strdup( p_input->psz_name );
777 /* Parse input string :
778 * [device][@[type][title]] */
779 while( *psz_parser && *psz_parser != '@' )
784 if( *psz_parser == '@' )
786 /* Found the divide between the source name and the
787 type+entry number. */
794 switch(*psz_parser) {
796 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
800 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
804 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
808 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
815 num = strtol( psz_parser, &psz_next, 10 );
816 if ( *psz_parser != '\0' && *psz_next == '\0')
825 /* No source specified, so figure it out. */
826 if( !p_input->psz_access ) return NULL;
828 psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
830 if( !psz_source || 0==strlen(psz_source) ) {
831 /* Scan for a CD-ROM drive with a VCD in it. */
832 char **cd_drives = cdio_get_devices_with_cap(NULL,
833 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
834 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
836 if (NULL == cd_drives) return NULL;
837 if (cd_drives[0] == NULL) {
838 cdio_free_device_list(cd_drives);
841 psz_source = strdup(cd_drives[0]);
842 cdio_free_device_list(cd_drives);
846 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
847 "source=%s entry=%d type=%d",
848 psz_source, p_itemid->num, p_itemid->type);
854 Set's start origin subsequent seeks/reads
857 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
858 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
860 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
862 p_vcd->origin_lsn = origin_lsn;
863 p_vcd->cur_lsn = cur_lsn;
864 p_vcd->end_lsn = end_lsn;
865 p_vcd->cur_track = cur_track;
866 p_vcd->play_item.num = cur_entry;
867 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
869 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
870 "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
871 origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
873 p_input->stream.p_selected_area->i_tell =
874 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
876 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
877 "chapter", "Setting entry");
880 /*****************************************************************************
881 * vcd_Open: Opens a VCD device or file and returns an opaque handle
882 *****************************************************************************/
883 static vcdinfo_obj_t *
884 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
886 vcdinfo_obj_t *p_vcdobj;
889 if( !psz_dev ) return NULL;
891 /* Set where to log errors messages from libcdio. */
892 p_vcd_input = (input_thread_t *)p_this;
893 cdio_log_set_handler ( cdio_log_handler );
894 vcd_log_set_handler ( vcd_log_handler );
896 actual_dev=strdup(psz_dev);
897 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
907 /****************************************************************************
908 * VCDReadSector: Read a sector (2324 bytes)
909 ****************************************************************************/
911 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
912 lsn_t cur_lsn, byte_t * p_buffer )
915 uint8_t subheader [8];
916 uint8_t data [M2F2_SECTOR_SIZE];
918 vcdsector_t vcd_sector;
920 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
921 &vcd_sector, cur_lsn, true)
924 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
928 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
933 /****************************************************************************
934 Update the "varname" variable to i_num without triggering a callback.
935 ****************************************************************************/
937 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
938 const char *varname, const char *label)
942 if (NULL != p_vcd_input) {
943 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
944 dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
946 var_Change( p_input, varname, i_action, &val, NULL );
950 #define meta_info_add_str(title, str) \
952 dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str); \
953 input_AddInfo( p_cat, _(title), "%s", str ); \
956 #define meta_info_add_num(title, num) \
957 dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num); \
958 input_AddInfo( p_cat, _(title), "%d", num ); \
960 static void InformationCreate( input_thread_t *p_input )
962 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
963 input_info_category_t *p_cat;
965 p_cat = input_InfoCategory( p_input, "General" );
967 meta_info_add_str( "VCD Format", vcdinfo_get_format_version_str(p_vcd->vcd));
968 meta_info_add_str( "Album", vcdinfo_get_album_id(p_vcd->vcd));
969 meta_info_add_str( "Application",vcdinfo_get_application_id(p_vcd->vcd));
970 meta_info_add_str( "Preparer", vcdinfo_get_preparer_id(p_vcd->vcd));
971 meta_info_add_num( "Vol #", vcdinfo_get_volume_num(p_vcd->vcd));
972 meta_info_add_num( "Vol max #", vcdinfo_get_volume_count(p_vcd->vcd));
973 meta_info_add_str( "Volume Set", vcdinfo_get_volumeset_id(p_vcd->vcd));
974 meta_info_add_str( "Volume", vcdinfo_get_volume_id(p_vcd->vcd));
975 meta_info_add_str( "Publisher", vcdinfo_get_publisher_id(p_vcd->vcd));
976 meta_info_add_str( "System Id", vcdinfo_get_system_id(p_vcd->vcd));
977 meta_info_add_num( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd));
978 meta_info_add_num( "Entries", vcdinfo_get_num_entries(p_vcd->vcd));
979 meta_info_add_num( "Segments", vcdinfo_get_num_segments(p_vcd->vcd));
980 meta_info_add_num( "Tracks", vcdinfo_get_num_tracks(p_vcd->vcd));
984 #if FINISHED_PLAYLIST
986 VCDCreatePlayListItem(const input_thread_t *p_input,
987 thread_vcd_data_t *p_vcd,
988 playlist_t *p_playlist, unsigned int i_track,
989 char *psz_mrl, int psz_mrl_max,
990 const char *psz_source, int playlist_operation,
994 (vcdinfo_get_track_size(p_vcd->vcd, i_track) * 8 * 10000000)
995 / (400 * p_input->stream.control.i_rate) ;
997 char *config_varname = MODULE_STRING "-title-format";
999 snprintf(psz_mrl, psz_mrl_max, "%s%s@T%u",
1000 VCD_MRL_PREFIX, psz_source, i_track);
1003 p_title = VCDFormatStr(p_input, p_vcd,
1004 config_GetPsz( p_input, config_varname ),
1010 playlist_AddExt( p_playlist, psz_mrl, p_title, i_duration,
1011 0, 0, playlist_operation, i_pos );
1015 VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1016 const char *psz_source )
1019 playlist_t * p_playlist;
1021 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
1022 strlen("@T") + strlen("100") + 1;
1024 psz_mrl = malloc( psz_mrl_max );
1026 if( psz_mrl == NULL )
1028 msg_Warn( p_input, "out of memory" );
1032 p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1036 msg_Warn( p_input, "can't find playlist" );
1041 if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
1042 /* May fill out more information when the playlist user interface becomes
1045 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, p_vcd->cur_track,
1046 psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
1047 p_playlist->i_index);
1050 playlist_Delete( p_playlist, p_playlist->i_index);
1052 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
1054 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, i, psz_mrl,
1055 psz_mrl_max, psz_source, PLAYLIST_APPEND,
1060 playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
1064 vlc_object_release( p_playlist );
1070 /*****************************************************************************
1072 *****************************************************************************/
1074 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
1075 vlc_value_t oldval, vlc_value_t val, void *p_data )
1077 thread_vcd_data_t *p_vcd;
1079 if (NULL == p_vcd_input) return VLC_EGENERIC;
1081 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1083 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
1084 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
1085 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1087 p_vcd->i_debug = val.i_int;
1091 /*****************************************************************************
1093 read in meta-information about VCD: the number of tracks, segments,
1094 entries, size and starting information. Then set up state variables so
1095 that we read/seek starting at the location specified.
1097 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1098 and VLC_EGENERIC for some other error.
1099 *****************************************************************************/
1101 E_(Open) ( vlc_object_t *p_this )
1103 input_thread_t * p_input = (input_thread_t *)p_this;
1104 thread_vcd_data_t * p_vcd;
1106 vcdinfo_itemid_t itemid;
1109 p_input->pf_read = VCDRead;
1110 p_input->pf_seek = VCDSeek;
1111 p_input->pf_set_area = VCDSetArea;
1112 p_input->pf_set_program = VCDSetProgram;
1114 p_vcd = malloc( sizeof(thread_vcd_data_t) );
1118 LOG_ERR ("out of memory" );
1122 p_input->p_access_data = (void *)p_vcd;
1123 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1124 psz_source = VCDParse( p_input, &itemid );
1126 if ( NULL == psz_source )
1129 return( VLC_EGENERIC );
1132 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
1134 p_vcd->p_segments = NULL;
1135 p_vcd->p_entries = NULL;
1138 p_input->i_mtu = VCD_DATA_ONCE;
1140 vlc_mutex_lock( &p_input->stream.stream_lock );
1142 /* If we are here we can control the pace... */
1143 p_input->stream.b_pace_control = 1;
1145 p_input->stream.b_seekable = 1;
1146 p_input->stream.p_selected_area->i_size = 0;
1147 p_input->stream.p_selected_area->i_tell = 0;
1149 vlc_mutex_unlock( &p_input->stream.stream_lock );
1151 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1153 msg_Warn( p_input, "could not open %s", psz_source );
1157 /* Get track information. */
1158 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
1159 vcdinfo_get_cd_image(p_vcd->vcd),
1160 &p_vcd->p_sectors );
1161 if( p_vcd->num_tracks < 0 )
1162 LOG_ERR ("unable to count tracks" );
1163 else if( p_vcd->num_tracks <= 1 )
1164 LOG_ERR ("no movie tracks found" );
1165 if( p_vcd->num_tracks <= 1)
1167 vcdinfo_close( p_vcd->vcd );
1171 /* Set stream and area data */
1172 vlc_mutex_lock( &p_input->stream.stream_lock );
1174 /* Initialize ES structures */
1175 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1177 /* disc input method */
1178 p_input->stream.i_method = INPUT_METHOD_VCD;
1180 p_input->stream.i_area_nb = 1;
1183 /* Initialize segment information. */
1184 VCDSegments( p_input );
1186 /* Initialize track area information. */
1187 VCDTracks( p_input );
1189 if( VCDEntryPoints( p_input ) < 0 )
1191 msg_Warn( p_input, "could not read entry points, will not use them" );
1192 p_vcd->b_valid_ep = false;
1195 if( VCDLIDs( p_input ) < 0 )
1197 msg_Warn( p_input, "could not read entry LIDs" );
1200 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1202 vlc_mutex_unlock( &p_input->stream.stream_lock );
1204 if ( ! b_play_ok ) {
1205 vcdinfo_close( p_vcd->vcd );
1209 if( !p_input->psz_demux || !*p_input->psz_demux )
1212 p_input->psz_demux = "vcdx";
1214 p_input->psz_demux = "ps";
1218 p_vcd->p_intf = intf_Create( p_input, "vcdx" );
1219 p_vcd->p_intf->b_block = VLC_FALSE;
1220 intf_RunThread( p_vcd->p_intf );
1222 InformationCreate( p_input );
1224 #if FINISHED_PLAYLIST
1225 VCDFixupPlayList( p_input, p_vcd, psz_source );
1234 return VLC_EGENERIC;
1237 /*****************************************************************************
1238 * Close: closes VCD releasing allocated memory.
1239 *****************************************************************************/
1241 E_(Close) ( vlc_object_t *p_this )
1243 input_thread_t * p_input = (input_thread_t *)p_this;
1244 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1246 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1247 vcdinfo_close( p_vcd->vcd );
1249 free( p_vcd->p_entries );
1250 free( p_vcd->p_segments );
1252 /* For reasons that are a mystery to me we don't have to deal with
1253 stopping, and destroying the p_vcd->p_intf thread. And if we do
1254 it causes problems upstream.
1256 if( p_vcd->p_intf != NULL )
1258 p_vcd->p_intf = NULL;
1262 p_input->p_access_data = NULL;