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.3 2003/11/20 03:56:22 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;
90 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
91 vlc_value_t oldval, vlc_value_t val, void *p_data )
93 thread_vcd_data_t *p_vcd;
95 if (NULL == p_vcd_input) return VLC_EGENERIC;
97 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
99 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
100 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
101 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
103 p_vcd->i_debug = val.i_int;
107 /* process messages that originate from libcdio. */
109 cdio_log_handler (cdio_log_level_t level, const char message[])
111 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
115 if (p_vcd->i_debug & INPUT_DBG_CDIO)
116 msg_Dbg( p_vcd_input, message);
119 msg_Warn( p_vcd_input, message);
122 case CDIO_LOG_ASSERT:
123 msg_Err( p_vcd_input, message);
126 msg_Warn( p_vcd_input, message,
127 _("The above message had unknown vcdimager log level"),
133 /* process messages that originate from vcdinfo. */
135 vcd_log_handler (vcd_log_level_t level, const char message[])
137 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
141 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
142 msg_Dbg( p_vcd_input, message);
145 msg_Warn( p_vcd_input, message);
149 msg_Err( p_vcd_input, message);
152 msg_Warn( p_vcd_input, "%s\n%s %d", message,
153 _("The above message had unknown vcdimager log level"),
160 * Data reading functions
163 /*****************************************************************************
165 read in meta-information about VCD: the number of tracks, segments,
166 entries, size and starting information. Then set up state variables so
167 that we read/seek starting at the location specified.
169 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
170 and VLC_EGENERIC for some other error.
171 *****************************************************************************/
173 E_(VCDOpen) ( vlc_object_t *p_this )
175 input_thread_t * p_input = (input_thread_t *)p_this;
176 thread_vcd_data_t * p_vcd;
178 vcdinfo_itemid_t itemid;
181 p_input->pf_read = VCDRead;
182 p_input->pf_seek = VCDSeek;
183 p_input->pf_set_area = VCDSetArea;
184 p_input->pf_set_program = VCDSetProgram;
186 p_vcd = malloc( sizeof(thread_vcd_data_t) );
190 LOG_ERR ("out of memory" );
194 p_input->p_access_data = (void *)p_vcd;
195 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
196 psz_source = VCDParse( p_input, &itemid );
198 if ( NULL == psz_source )
201 return( VLC_EGENERIC );
204 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
206 p_vcd->p_segments = NULL;
207 p_vcd->p_entries = NULL;
210 p_input->i_mtu = VCD_DATA_ONCE;
212 vlc_mutex_lock( &p_input->stream.stream_lock );
214 /* If we are here we can control the pace... */
215 p_input->stream.b_pace_control = 1;
217 p_input->stream.b_seekable = 1;
218 p_input->stream.p_selected_area->i_size = 0;
219 p_input->stream.p_selected_area->i_tell = 0;
221 vlc_mutex_unlock( &p_input->stream.stream_lock );
223 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
225 msg_Warn( p_input, "could not open %s", psz_source );
231 /* Get track information. */
232 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
233 vcdinfo_get_cd_image(p_vcd->vcd),
236 if( p_vcd->num_tracks < 0 )
237 LOG_ERR ("unable to count tracks" );
238 else if( p_vcd->num_tracks <= 1 )
239 LOG_ERR ("no movie tracks found" );
240 if( p_vcd->num_tracks <= 1)
242 vcdinfo_close( p_vcd->vcd );
247 /* Set stream and area data */
248 vlc_mutex_lock( &p_input->stream.stream_lock );
250 /* Initialize ES structures */
251 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
253 /* disc input method */
254 p_input->stream.i_method = INPUT_METHOD_VCD;
256 p_input->stream.i_area_nb = 1;
259 /* Initialize segment information. */
260 VCDSegments( p_input );
262 /* Initialize track area information. */
263 VCDTracks( p_input );
265 if( VCDEntryPoints( p_input ) < 0 )
267 msg_Warn( p_input, "could not read entry points, will not use them" );
268 p_vcd->b_valid_ep = false;
271 if( VCDLIDs( p_input ) < 0 )
273 msg_Warn( p_input, "could not read entry LIDs" );
276 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
278 vlc_mutex_unlock( &p_input->stream.stream_lock );
281 vcdinfo_close( p_vcd->vcd );
286 if( !p_input->psz_demux || !*p_input->psz_demux )
289 p_input->psz_demux = "vcdx";
291 p_input->psz_demux = "ps";
295 p_vcd->p_intf = intf_Create( p_input, "vcdx" );
296 p_vcd->p_intf->b_block = VLC_FALSE;
297 intf_RunThread( p_vcd->p_intf );
302 /*****************************************************************************
303 * VCDClose: closes VCD releasing allocated memory.
304 *****************************************************************************/
306 E_(VCDClose) ( vlc_object_t *p_this )
308 input_thread_t * p_input = (input_thread_t *)p_this;
309 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
311 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
312 vcdinfo_close( p_vcd->vcd );
314 free( p_vcd->p_entries );
315 free( p_vcd->p_segments );
317 /* For reasons that are a mystery to me we don't have to deal with
318 stopping, and destroying the p_vcd->p_intf thread. And if we do
319 it causes problems upstream.
321 if( p_vcd->p_intf != NULL )
323 p_vcd->p_intf = NULL;
327 p_input->p_access_data = NULL;
331 /*****************************************************************************
332 * VCDRead: reads i_len bytes from the VCD into p_buffer.
333 *****************************************************************************
334 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
336 *****************************************************************************/
338 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
340 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
344 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
348 dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn );
350 /* Compute the number of blocks we have to read */
352 i_blocks = i_len / M2F2_SECTOR_SIZE;
354 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
357 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
358 vcdplayer_read_status_t read_status;
360 /* We've run off of the end of this entry. Do we continue or stop? */
361 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
362 "end reached, cur: %u", p_vcd->cur_lsn );
364 read_status = vcdplayer_pbc_is_on( p_vcd )
365 ? vcdplayer_pbc_nav( p_input )
366 : vcdplayer_non_pbc_nav( p_input );
368 switch (read_status) {
370 /* End reached. Return NULL to indicated this. */
372 /* Some sort of error. */
375 case READ_STILL_FRAME:
377 /* Reached the end of a still frame. */
379 byte_t * p_buf = p_buffer;
380 pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
382 p_buf += (i_index*M2F2_SECTOR_SIZE);
383 memset(p_buf, 0, M2F2_SECTOR_SIZE);
386 dbg_print(INPUT_DBG_STILL, "Handled still event\n");
388 /* p_vcd->p_intf->b_end_of_cell = true; */
389 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
391 vlc_mutex_lock( &p_input->stream.stream_lock );
393 p_pgrm = p_input->stream.p_selected_program;
394 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
396 vlc_mutex_unlock( &p_input->stream.stream_lock );
398 input_ClockManageControl( p_input, p_pgrm, 0 );
400 return i_read + M2F2_SECTOR_SIZE;
408 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
410 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
412 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
419 if( p_vcd->b_valid_ep &&
420 /* FIXME kludge so that read does not update chapter
421 * when a manual chapter change was requested and not
422 * yet accomplished */
423 !p_input->stream.p_new_area )
425 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
427 vlc_mutex_lock( &p_input->stream.stream_lock );
429 if( i_entry < p_vcd->num_entries &&
430 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
432 dbg_print( INPUT_DBG_PBC,
433 "new entry, i_entry %d, sector %d, es %d",
434 i_entry, p_vcd->cur_lsn,
435 p_vcd->p_entries[i_entry] );
436 p_vcd->play_item.num =
437 ++ p_input->stream.p_selected_area->i_part;
438 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
439 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
440 "chapter", "Setting entry" );
442 vlc_mutex_unlock( &p_input->stream.stream_lock );
445 i_read += M2F2_SECTOR_SIZE;
448 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
450 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
451 p_vcd->cur_lsn, p_last_sector ) < 0 )
453 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
457 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
458 p_last_sector, i_len % M2F2_SECTOR_SIZE );
459 i_read += i_len % M2F2_SECTOR_SIZE;
466 /*****************************************************************************
467 * VCDSetProgram: Does nothing since a VCD is mono_program
468 *****************************************************************************/
470 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
472 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
473 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
478 /*****************************************************************************
479 * VCDSetArea: initialize internal data structures and input stream data
480 so set subsequent reading and seeking to reflect that we are
481 at track x, entry or segment y.
482 This is called for each user navigation request, e.g. the GUI
483 Chapter/Title selections or in initial MRL parsing.
484 ****************************************************************************/
486 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
488 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
489 unsigned int i_entry = p_area->i_part;
490 track_t i_track = p_area->i_id;
491 int old_seekable = p_input->stream.b_seekable;
492 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
494 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
495 "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
496 i_track, i_entry, old_seekable,
497 (long unsigned int) p_area,
498 (long unsigned int) p_input->stream.p_selected_area );
500 /* we can't use the interface slider until initilization is complete */
501 p_input->stream.b_seekable = 0;
503 if( p_area != p_input->stream.p_selected_area )
507 /* If is the result of a track change, make the entry valid. */
508 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
509 i_entry = p_area->i_plugin_data;
511 /* Change the default area */
512 p_input->stream.p_selected_area = p_area;
514 /* Update the navigation variables without triggering a callback */
515 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
518 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
519 for( i = p_area->i_plugin_data; i < i_nb; i++ )
521 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
522 "chapter", "Adding entry choice");
527 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
528 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
531 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
532 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
533 p_vcd->p_sectors[i_track+1],
536 p_input->stream.b_seekable = old_seekable;
537 /* warn interface that something has changed */
538 p_input->stream.b_changed = 1;
544 /****************************************************************************
546 ****************************************************************************/
548 VCDSeek( input_thread_t * p_input, off_t i_off )
550 thread_vcd_data_t * p_vcd;
551 unsigned int i_entry=0; /* invalid entry */
553 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
555 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
557 vlc_mutex_lock( &p_input->stream.stream_lock );
558 #define p_area p_input->stream.p_selected_area
560 if( p_vcd->b_valid_ep )
562 for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
564 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
566 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
567 "chapter", "Setting entry" );
571 p_vcd->play_item.num = p_area->i_part = i_entry;
572 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
576 p_input->stream.p_selected_area->i_tell = i_off;
578 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
579 "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
580 p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
581 p_input->stream.p_selected_area->i_start, i_entry );
583 vlc_mutex_unlock( &p_input->stream.stream_lock );
586 /*****************************************************************************
587 VCDPlay: set up internal structures so seeking/reading places an item.
588 itemid: the thing to play.
589 user_entry: true if itemid is a user selection (rather than internally-
590 generated selection such as via PBC) in which case we may have to adjust
591 for differences in numbering.
592 *****************************************************************************/
594 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
596 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
597 input_area_t * p_area;
601 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
602 itemid.num, itemid.type);
604 #define area p_input->stream.pp_areas
606 switch (itemid.type) {
607 case VCDINFO_ITEM_TYPE_TRACK:
609 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
612 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
613 LOG_ERR ("Invalid track number %d", itemid.num );
616 p_area = area[itemid.num];
617 p_area->i_part = p_area->i_plugin_data;
618 p_input->stream.b_seekable = 1;
620 case VCDINFO_ITEM_TYPE_SEGMENT:
621 /* Valid segments go from 0...num_segments-1. */
622 if (itemid.num >= p_vcd->num_segments) {
623 LOG_ERR ( "Invalid segment number: %d", itemid.num );
626 vcdinfo_video_segment_type_t segtype =
627 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
629 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
630 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
631 (int) segtype, itemid.num);
634 p_area->i_part = itemid.num;
638 case VCDINFO_FILES_VIDEO_NTSC_STILL:
639 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
640 case VCDINFO_FILES_VIDEO_PAL_STILL:
641 case VCDINFO_FILES_VIDEO_PAL_STILL2:
642 p_input->stream.b_seekable = 0;
643 p_vcd->in_still = -5;
646 p_input->stream.b_seekable = 1;
652 case VCDINFO_ITEM_TYPE_LID:
653 /* LIDs go from 1..num_lids. */
654 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
655 LOG_ERR ( "Invalid LID number: %d", itemid.num );
658 p_vcd->cur_lid = itemid.num;
659 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
661 switch (p_vcd->pxd.descriptor_type) {
663 case PSD_TYPE_SELECTION_LIST:
664 case PSD_TYPE_EXT_SELECTION_LIST: {
665 vcdinfo_itemid_t trans_itemid;
666 uint16_t trans_itemid_num;
668 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
669 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
670 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
671 p_vcd->loop_count = 1;
672 p_vcd->loop_item = trans_itemid;
673 return VCDPlay( p_input, trans_itemid );
677 case PSD_TYPE_PLAY_LIST: {
678 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
680 return vcdplayer_inc_play_item(p_input)
681 ? VLC_SUCCESS : VLC_EGENERIC;
685 case PSD_TYPE_END_LIST:
686 case PSD_TYPE_COMMAND_LIST:
693 case VCDINFO_ITEM_TYPE_ENTRY:
694 /* Entries go from 0..num_entries-1. */
695 if (itemid.num >= p_vcd->num_entries) {
696 LOG_ERR ("Invalid entry number: %d", itemid.num );
699 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
700 p_area = area[cur_track];
701 p_area->i_part = itemid.num;
702 p_input->stream.b_seekable = 1;
706 LOG_ERR ("unknown entry type" );
710 VCDSetArea( p_input, p_area );
714 p_vcd->play_item = itemid;
716 dbg_print( (INPUT_DBG_CALL),
717 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
718 p_area->i_start, p_area->i_size,
719 p_area->i_tell, p_vcd->cur_lsn );
724 /*****************************************************************************
725 VCDEntryPoints: Reads the information about the entry points on the disc
726 and initializes area information with that.
727 Before calling this track information should have been read in.
728 *****************************************************************************/
730 VCDEntryPoints( input_thread_t * p_input )
732 thread_vcd_data_t * p_vcd;
734 unsigned int i, i_entry_index = 0;
735 unsigned int i_previous_track = CDIO_INVALID_TRACK;
737 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
739 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
743 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
745 if( p_vcd->p_entries == NULL )
747 LOG_ERR ("not enough memory for entry points treatment" );
751 p_vcd->num_entries = 0;
753 for( i = 0 ; i < i_nb ; i++ )
755 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
756 if( i_track <= p_input->stream.i_area_nb )
758 p_vcd->p_entries[i] =
759 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
760 p_input->stream.pp_areas[i_track]->i_part_nb ++;
762 /* if this entry belongs to a new track */
763 if( i_track != i_previous_track )
765 /* i_plugin_data is used to store the first entry of the area*/
766 p_input->stream.pp_areas[i_track]->i_plugin_data =
768 i_previous_track = i_track;
769 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
772 p_vcd->num_entries ++;
775 msg_Warn( p_input, "wrong track number found in entry points" );
777 p_vcd->b_valid_ep = true;
781 /*****************************************************************************
782 * VCDSegments: Reads the information about the segments the disc.
783 *****************************************************************************/
785 VCDSegments( input_thread_t * p_input )
787 thread_vcd_data_t * p_vcd;
789 unsigned int num_segments;
792 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
793 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
795 #define area p_input->stream.pp_areas
797 /* area 0 is reserved for segments. Set Absolute start offset
799 area[0]->i_plugin_data = 0;
800 input_DelArea( p_input, area[0] );
801 input_AddArea( p_input, 0, 0 );
803 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
804 * (off_t)M2F2_SECTOR_SIZE;
805 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
806 * (off_t)M2F2_SECTOR_SIZE;
808 /* Default Segment */
811 /* i_plugin_data is used to store which entry point is the first
812 of the track (area) */
813 area[0]->i_plugin_data = 0;
815 area[0]->i_part_nb = 0;
817 dbg_print( INPUT_DBG_MRL,
818 "area[0] id: %d, i_start: %lld, i_size: %lld",
819 area[0]->i_id, area[0]->i_start, area[0]->i_size );
821 if (num_segments == 0) return 0;
823 /* We have one additional segment allocated so we can get the size
824 by subtracting seg[i+1] - seg[i].
826 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
827 if( p_vcd->p_segments == NULL )
829 LOG_ERR ("not enough memory for segment treatment" );
833 /* Update the navigation variables without triggering a callback */
834 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
835 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
837 for( i = 0 ; i < num_segments ; i++ )
839 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
840 area[0]->i_part_nb ++;
841 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
842 "chapter", "Adding segment choice");
847 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
848 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
853 /*****************************************************************************
854 VCDTracks: initializes area information.
855 Before calling this track information should have been read in.
856 *****************************************************************************/
858 VCDTracks( input_thread_t * p_input )
860 thread_vcd_data_t * p_vcd;
863 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
865 #define area p_input->stream.pp_areas
867 /* We start area addressing for tracks at 1 since the default area 0
868 is reserved for segments */
870 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
872 /* Tracks are Program Chains */
873 input_AddArea( p_input, i, i );
875 /* Absolute start byte offset and byte size */
876 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
877 * (off_t)M2F2_SECTOR_SIZE;
878 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
879 * (off_t)M2F2_SECTOR_SIZE;
881 /* Current entry being played in track */
884 /* i_plugin_data is used to store which entry point is the first
885 * of the track (area) */
886 area[i]->i_plugin_data = 0;
888 dbg_print( INPUT_DBG_MRL,
889 "area[%d] id: %d, i_start: %lld, i_size: %lld",
890 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
898 /*****************************************************************************
899 VCDLIDs: Reads the LIST IDs from the LOT.
900 *****************************************************************************/
902 VCDLIDs( input_thread_t * p_input )
904 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
906 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
907 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
909 if (vcdinfo_read_psd (p_vcd->vcd)) {
911 vcdinfo_visit_lot (p_vcd->vcd, false);
915 We need to change libvcdinfo to be more robust when there are
916 problems reading the extended PSD. Given that area-highlighting and
917 selection features in the extended PSD haven't been implemented,
918 it's best then to not try to read this at all.
920 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
921 vcdinfo_visit_lot (p_vcd->vcd, true);
925 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
926 "num LIDs=%d", p_vcd->num_lids);
931 /*****************************************************************************
932 * VCDParse: parse command line
933 *****************************************************************************/
935 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
937 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
942 p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
946 /* On Win32 we want the VCD access plugin to be explicitly requested,
947 * we end up with lots of problems otherwise */
948 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
951 if( !p_input->psz_name )
956 psz_parser = psz_source = strdup( p_input->psz_name );
958 /* Parse input string :
959 * [device][@[type][title]] */
960 while( *psz_parser && *psz_parser != '@' )
965 if( *psz_parser == '@' )
967 /* Found the divide between the source name and the
968 type+entry number. */
975 switch(*psz_parser) {
977 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
981 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
985 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
989 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
996 num = strtol( psz_parser, &psz_next, 10 );
997 if ( *psz_parser != '\0' && *psz_next == '\0')
1004 if( !*psz_source ) {
1006 /* No source specified, so figure it out. */
1007 if( !p_input->psz_access ) return NULL;
1009 psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
1012 /* Scan for a CD with a VCD in it. */
1013 char **cd_drives = cdio_get_devices_with_cap(NULL,
1014 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
1015 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
1017 if (NULL == cd_drives) return NULL;
1018 if (cd_drives[0] == NULL) {
1019 cdio_free_device_list(cd_drives);
1022 psz_source = strdup(cd_drives[0]);
1023 cdio_free_device_list(cd_drives);
1027 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
1028 "source=%s entry=%d type=%d",
1029 psz_source, p_itemid->num, p_itemid->type);
1035 Set's start origin subsequent seeks/reads
1038 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
1039 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
1041 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1043 p_vcd->origin_lsn = origin_lsn;
1044 p_vcd->cur_lsn = cur_lsn;
1045 p_vcd->end_lsn = end_lsn;
1046 p_vcd->cur_track = cur_track;
1047 p_vcd->play_item.num = cur_entry;
1048 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1050 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
1051 "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
1052 origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
1054 p_input->stream.p_selected_area->i_tell =
1055 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
1057 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
1058 "chapter", "Setting entry");
1061 /*****************************************************************************
1062 * vcd_Open: Opens a VCD device or file and returns an opaque handle
1063 *****************************************************************************/
1064 static vcdinfo_obj_t *
1065 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
1067 vcdinfo_obj_t *p_vcdobj;
1070 if( !psz_dev ) return NULL;
1072 /* Set where to log errors messages from libcdio. */
1073 p_vcd_input = (input_thread_t *)p_this;
1074 cdio_log_set_handler ( cdio_log_handler );
1075 vcd_log_set_handler ( vcd_log_handler );
1077 actual_dev=strdup(psz_dev);
1078 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
1088 /****************************************************************************
1089 * VCDReadSector: Read a sector (2324 bytes)
1090 ****************************************************************************/
1092 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
1093 lsn_t cur_lsn, byte_t * p_buffer )
1096 uint8_t subheader [8];
1097 uint8_t data [M2F2_SECTOR_SIZE];
1099 vcdsector_t vcd_sector;
1101 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
1102 &vcd_sector, cur_lsn, true)
1105 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
1109 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
1114 /****************************************************************************
1115 Update the "varname" variable to i_num without triggering a callback.
1116 ****************************************************************************/
1118 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
1119 const char *varname, const char *label)
1123 if (NULL != p_vcd_input) {
1124 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1125 dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
1127 var_Change( p_input, varname, i_action, &val, NULL );