/***************************************************************************** VCDEntryPoints: Reads the information about the entry points on the disc and initializes area information with that. Before calling this track information should have been read in. *****************************************************************************/ static bool VCDEntryPoints( access_t * p_access ) { if (!p_access || !p_access->p_sys) return false; vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys; const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdplayer->vcd); const track_t i_last_track = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd)) + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd)); unsigned int i; if (0 == i_entries) { LOG_ERR ("no entires found -- something is wrong" ); return false; } p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries ); if( p_vcdplayer->p_entries == NULL ) { LOG_ERR ("not enough memory for entry points treatment" ); return false; } p_vcdplayer->i_entries = i_entries; for( i = 0 ; i < i_entries ; i++ ) { const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i); if( i_track <= i_last_track ) { seekpoint_t *s = vlc_seekpoint_New(); char psz_entry[100]; snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i ); p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i); s->psz_name = strdup(psz_entry); s->i_byte_offset = (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd,i_track)) * M2F2_SECTOR_SIZE; dbg_print( INPUT_DBG_MRL, "%s, lsn %d, byte_offset %"PRId64"", s->psz_name, p_vcdplayer->p_entries[i], s->i_byte_offset); TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint, p_vcdplayer->p_title[i_track-1]->seekpoint, s ); } else msg_Warn( p_access, "wrong track number found in entry points" ); } p_vcdplayer->b_valid_ep = true; return true; }
/*! Set reading to play an entry */ static void _vcdplayer_set_entry(access_t * p_access, unsigned int num) { vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys; vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo); if (num >= i_entries) { LOG_ERR("%s %d", "bad entry number", num); return; } else { vcdinfo_itemid_t itemid; itemid.num = num; itemid.type = VCDINFO_ITEM_TYPE_ENTRY; p_vcdplayer->i_still = 0; VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(p_vcdinfo, num), vcdinfo_get_track(p_vcdinfo, num), &itemid); dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u", p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn); } }
/***************************************************************************** * vcd_Open: Opens a VCD device or file initializes, a list of tracks, segements and entry lsns and sizes and returns an opaque handle. *****************************************************************************/ static vcdinfo_obj_t * vcd_Open( vlc_object_t *p_this, const char *psz_dev ) { access_t *p_access = (access_t *)p_this; vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys; vcdinfo_obj_t *p_vcdobj; char *actual_dev; unsigned int i; dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev); if( !psz_dev ) return NULL; actual_dev= ToLocaleDup(psz_dev); if( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) != VCDINFO_OPEN_VCD) { free(actual_dev); return NULL; } free(actual_dev); /* Save summary info on tracks, segments and entries... */ if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) { p_vcdplayer->track = (vcdplayer_play_item_info_t *) calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t)); for (i=0; i<p_vcdplayer->i_tracks; i++) { unsigned int track_num=i+1; p_vcdplayer->track[i].size = vcdinfo_get_track_sect_count(p_vcdobj, track_num); p_vcdplayer->track[i].start_LSN = vcdinfo_get_track_lsn(p_vcdobj, track_num); } } else p_vcdplayer->track = NULL; if( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) { p_vcdplayer->entry = (vcdplayer_play_item_info_t *) calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t)); for (i=0; i<p_vcdplayer->i_entries; i++) { p_vcdplayer->entry[i].size = vcdinfo_get_entry_sect_count(p_vcdobj, i); p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i); } } else p_vcdplayer->entry = NULL; if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) { p_vcdplayer->segment = (vcdplayer_play_item_info_t *) calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t)); for (i=0; i<p_vcdplayer->i_segments; i++) { p_vcdplayer->segment[i].size = vcdinfo_get_seg_sector_count(p_vcdobj, i); p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i); } } else p_vcdplayer->segment = NULL; return p_vcdobj; }
/***************************************************************************** VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that. NULL is returned if something went wrong. *****************************************************************************/ static block_t * VCDReadBlock( access_t * p_access ) { vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; const int i_blocks = p_vcdplayer->i_blocks_per_read; block_t *p_block; int i_read; uint8_t *p_buf; dbg_print( (INPUT_DBG_LSN), "lsn: %lu", (long unsigned int) p_vcdplayer->i_lsn ); /* Allocate a block for the reading */ if( !( p_block = block_Alloc( i_blocks * M2F2_SECTOR_SIZE ) ) ) { msg_Err( p_access, "cannot get a new block of size: %i", i_blocks * M2F2_SECTOR_SIZE ); block_Release( p_block ); return NULL; } p_buf = (uint8_t *) p_block->p_buffer; for ( i_read = 0 ; i_read < i_blocks ; i_read++ ) { vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf); p_access->info.i_pos += M2F2_SECTOR_SIZE; switch ( read_status ) { case READ_END: /* End reached. Return NULL to indicated this. */ /* We also set the postion to the end so the higher level (demux?) doesn't try to keep reading. If everything works out right this shouldn't have to happen. */ #if 0 if( p_access->info.i_pos != p_access->info.i_size ) { msg_Warn( p_access, "At end but pos (%llu) is not size (%llu). Adjusting.", p_access->info.i_pos, p_access->info.i_size ); p_access->info.i_pos = p_access->info.i_size; } #endif block_Release( p_block ); return NULL; case READ_ERROR: /* Some sort of error. Should we increment lsn? to skip block? */ block_Release( p_block ); return NULL; case READ_STILL_FRAME: /* FIXME The below should be done in an event thread. Until then... */ #if 1 msleep( INT64_C(1000) * *p_buf ); VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track, &(p_vcdplayer->play_item)); // p_vcd->in_still = false; dbg_print(INPUT_DBG_STILL, "still wait time done"); #endif block_Release( p_block ); return NULL; default: case READ_BLOCK: /* Read buffer */ break; } p_buf += M2F2_SECTOR_SIZE; /* Update seekpoint */ if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type ) { size_t i_entry = p_vcdplayer->play_item.num+1; lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry); if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN ) { dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change to %zu, current LSN %u >= end %u", i_entry, p_vcdplayer->i_lsn, i_lsn); p_vcdplayer->play_item.num = i_entry; VCDSetOrigin( p_access, i_lsn, p_vcdplayer->i_track, &(p_vcdplayer->play_item) ); } } } return p_block; }